47
Strategies for End-to-End Web Apps Testing Ariya Hidayat

Strategies for End-to-End Web Apps Testing

Embed Size (px)

DESCRIPTION

Developing complex web applications without systematic strategies for its quality assurance will lead to maintenance nightmares. End-to-end testing, from the moment the implementation is being planned up to the stage of deployment, requires careful planning and a suitable set of tools. In this talk, the use of various tools to assist such testing strategies will be uncovered. This involves the use of scriptable headless page automation (PhantomJS, Zombie.js, Selenium) for fast smoke testing as part of the precommit process and for more comprehensive preflight checks in the continuous integration system. In addition, a wide spectrum of testing possibilities will be achieved with extra tools such as static code analyzer, full-stack execution logger, profiler, and code coverage/instrumentation.

Citation preview

Page 1: Strategies for End-to-End Web Apps Testing

Strategies for End-to-EndWeb Apps Testing Ariya Hidayat

Page 2: Strategies for End-to-End Web Apps Testing

Amazon KindleCloud Reader

Financial Times

Page 3: Strategies for End-to-End Web Apps Testing

Edit

Develop

QA

Page 4: Strategies for End-to-End Web Apps Testing

Code Editing

Page 5: Strategies for End-to-End Web Apps Testing

Avoid silly mistakes

Write readable code

Do not provoke ambiguities

Improve future maintenance

Learn better code pattern

Page 6: Strategies for End-to-End Web Apps Testing

JavaScript Engine Building Blocks

Virtual Machine/

InterpreterParser

Runtime

Source

Syntax Tree

Built-in objects,host objects, ...

Fast and conservative

Page 7: Strategies for End-to-End Web Apps Testing

Parsing Stage

keyword equal sign semicolon

identifier number

var answer = 42;

Variable Declaration

Identifier Literal Constant

Page 8: Strategies for End-to-End Web Apps Testing

JavaScript Parser (Written in JavaScript)

UglifyJS

ZeParser

Esprima

TraceurNarcissus

Es-Lab

Page 9: Strategies for End-to-End Web Apps Testing

Syntax Tree Visualization

answer = 42

Page 10: Strategies for End-to-End Web Apps Testing

Style Formatter https://github.com/fawek/codepainter

CodePainterSource

Sample code

Formatted source

Infer coding styles

IndentationQuote for string literalWhitespace

Page 11: Strategies for End-to-End Web Apps Testing

Code Outline Eclipse

FunctionsVariables

Page 12: Strategies for End-to-End Web Apps Testing

Application Structure

Ext.define('My.sample.Person', { name: 'Mr. Unknown',  age: 42,

constructor: function(name) {},  walk: function(steps) {} run: function(steps) {}

});

Class manifest

{ className: 'My.sample.Person', functions: ['walk', 'run'], properties: ['name', 'age']}

Page 13: Strategies for End-to-End Web Apps Testing

Content Assist (aka Intellisense aka Autocomplete)

Eclipse

http://contraptionsforprogramming.blogspot.com/2012/02/better-javascript-content-assist-in.html

Page 14: Strategies for End-to-End Web Apps Testing

Error Tolerant

var msg = "Hello’;

person..age = 18;

 if (person.

 'use strict';with (person) {}

Mismatched quote

Too many dots

Incomplete, still typing

Strict mode violation

Page 15: Strategies for End-to-End Web Apps Testing

Code Linting

var fs = require('fs'), esprima = require('./esprima'), files = process.argv.splice(2); files.forEach(function (filename) { var content = fs.readFileSync(filename, 'utf-8'), syntax = esprima.parse(content, { loc: true });  JSON.stringify(syntax, function (key, value) { if (key === 'test' && value.operator === '==') console.log('Line', value.loc.start.line); return value; });});

if (x == 9) { // do Something}

Not a strict equal

Page 16: Strategies for End-to-End Web Apps Testing

Copy Paste Mistake

function inside(point, rect) { return (point.x >= rect.x1) && (point.y >= rect.y1) && (point.x <= rect.x2) && (point.y <= rect.y1);}

Wrong check

Page 17: Strategies for End-to-End Web Apps Testing

“Boolean Trap” Finder

Can you make up your mind? treeItem.setState(true, false);

event.initKeyEvent("keypress", true, true, null, null, false, false, false, false, 9, 0);

The more the merrier

Obfuscated choice var volumeSlider = new Slider(false);

Double-negative component.setHidden(false);filter.setCaseInsensitive(false);

http://ariya.ofilabs.com/2011/08/hall-of-api-shame-boolean-trap.html

Page 18: Strategies for End-to-End Web Apps Testing

Refactoring Helper

// Add two numbersfunction add(firt, two) { return firt + two;}

// Add two numbersfunction add(first, two) { return first + two;}

Page 19: Strategies for End-to-End Web Apps Testing

Syntax = Message

var Foo = (function () { return { bar: function (x, y) { // do Something } };};

module Foo { export function bar (x, y) { // do something }}

ES 5.1 HarmonyToday ES 6/7, Future

Page 20: Strategies for End-to-End Web Apps Testing

Transpilation

// Object literal property shorthand.function Point(x, y) { return { x: x, y: y };}

// Object literal property shorthand.function Point(x, y) { return { x, y };}

Harmony

ES 5.1

Page 21: Strategies for End-to-End Web Apps Testing

Development

Page 22: Strategies for End-to-End Web Apps Testing

Unit Test Framework

http://www.trollquotes.org/image/5-gandalf-troll-quote.jpg

Page 23: Strategies for End-to-End Web Apps Testing

Automatic Reload

Modified source Reload content

Page 24: Strategies for End-to-End Web Apps Testing

Remote Interactionhttp://www.sencha.com/blog/remote-javascript-debugging-on-android/

Weinre, Adobe Shadow, Remote Web Inspector,...

Page 25: Strategies for End-to-End Web Apps Testing

Fast Smoke Test

Feedback Cycle

Page 26: Strategies for End-to-End Web Apps Testing

Precommit Check

forget to run

the tests

Typical Scenario

This is awesome!

Git: precommit hookhttp://ariya.ofilabs.com/2012/03/git-pre-commit-hook-and-smoke-testing.html

Page 27: Strategies for End-to-End Web Apps Testing

Zombie.js

var Browser = require("zombie"); browser = new Browser();browser.visit("http://mobileconference.nl", function () { console.log(browser.text("title"));});

Page 28: Strategies for End-to-End Web Apps Testing

PhantomJS (Headless WebKit)

Display

Paint

Layout

Normal Browser

Display

Paint

Layout

XHeadless Operation

Page 29: Strategies for End-to-End Web Apps Testing

Screen Capture = Pixel-Perfect Comparison

phantomjs rasterize.js URL output

Page 30: Strategies for End-to-End Web Apps Testing

CasperJS

var casper = require('casper').create();

casper.start('http://www.mobileconference.nl/', function() { this.echo('Page title is: ' + this.evaluate(function() { return document.title; }), 'INFO');});

casper.run();

Page 31: Strategies for End-to-End Web Apps Testing

Postcommit Quality Metrics

Quality Factor 1

Quality Factor 2

Check-in

Page 32: Strategies for End-to-End Web Apps Testing

Identifier Length Distribution

http://ariya.ofilabs.com/2012/05/javascript-identifier-length-distribution.html

0

250

500

750

0 5 10 15 20 25 30 35 40 45

mean of the identifier length is 8.27 characters

prototype-1.7.0.0.js SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDINGprototype-1.7.0.0.js MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED jquery-1.7.1.js subtractsBorderForOverflowNotVisiblejquery.mobile-1.0.js getClosestElementWithVirtualBindingprototype-1.7.0.0.js HAS_EXTENDED_CREATE_ELEMENT_SYNTAX

Page 33: Strategies for End-to-End Web Apps Testing

Statement Distribution

http://ariya.ofilabs.com/2012/04/most-popular-javascript-statements.html

ExpressionStatementBlockStatement

IfStatementReturnStatement

VariableDeclarationFunctionDeclaration

ForStatementForInStatementWhileStatementBreakStatement

TryStatementEmptyStatementThrowStatementSwitchStatement

ContinueStatementDoWhileStatementLabeledStatement 6

12

25

35

38

66

84

115

131

143

293

371

2116

2878

3063

6353

6728

var fs = require('fs'), esprima = require('esprima'), files = process.argv.splice(2); files.forEach(function (filename) { var content = fs.readFileSync(filename, 'utf-8'), syntax = esprima.parse(content);  JSON.stringify(syntax, function (key, value) { if (key === 'type') { if (value.match(/Declaration$/) || value.match(/Statement$/)) { console.log(value); } } return value; });});

Page 34: Strategies for End-to-End Web Apps Testing

QA

Page 35: Strategies for End-to-End Web Apps Testing

Platform Proliferation

Page 36: Strategies for End-to-End Web Apps Testing

BusterJS

Server Interface

Test Suite

Test Server

Page 37: Strategies for End-to-End Web Apps Testing

Selenium

WebDriver

WebDriver Client

Opera WebDriver

Firefox WebDriver Chrome

WebDriver

Page 38: Strategies for End-to-End Web Apps Testing

Code Coverage

http://ariya.ofilabs.com/2012/03/javascript-code-coverage-and-esprima.html

x = 42;if (false) x = -1;

https://github.com/itay/node-coverhttps://github.com/coveraje/coverajehttps://github.com/pmlopes/coberturajs

Page 39: Strategies for End-to-End Web Apps Testing

Instrumentation for Code Coverage

http://itay.github.com/snug_codecoverage_slides/

var a = 5;{ __statement_ZyyqFc(1); var a = 5;}

foo();{ __statement_ZyyqFc(2); __expression_kC$jur(3), foo();}

function foo() { ...};

function foo() { __block_n53cJc(1); ...}

Statement

Expression

Block

Page 40: Strategies for End-to-End Web Apps Testing

Performance via Benchmarks.js

var suite = new Benchmark.Suite;

suite.add('String#indexOf', function() { 'Hello World!'.indexOf('o') > -1;}).on('complete', function() { console.log('Fastest is ' + this.filter('fastest').pluck('name'));}).run();

JSPerf.com

Page 41: Strategies for End-to-End Web Apps Testing

Performance Baseline

Application revision

Exec

utio

n tim

e

Baseline

Page 42: Strategies for End-to-End Web Apps Testing

Scalability via Run-time Complexity Analysis

http://ariya.ofilabs.com/2012/01/scalable-web-apps-the-complexity-issue.html

Array.prototype.swap = function (i, j) { var k = this[i]; this[i] = this[j]; this[j] = k;}

Array.prototype.swap = function (i, j) {Log({ name: 'Array.prototype.swap', lineNumber: 1, range: [23, 94] }); var k = this[i]; this[i] = this[j]; this[j] = k;}

Page 43: Strategies for End-to-End Web Apps Testing

Execution Tracing

http://ariya.ofilabs.com/2012/02/tracking-javascript-execution-during-startup.html

https://gist.github.com/1823129jQuery Mobile startup log

4640 function calls

jquery.js 26 jQuery jquery.js 103 init undefined, undefined, [object Object] jquery.js 274 each (Function) jquery.js 631 each [object Object], (Function), undefined jquery.js 495 isFunction [object Object] jquery.js 512 type [object Object]jquery.mobile.js 1857 [Anonymous]jquery.mobile.js 642 [Anonymous]jquery.mobile.js 624 enableMouseBindingsjquery.mobile.js 620 disableTouchBindings

Page 44: Strategies for End-to-End Web Apps Testing

Wrap-up

Page 45: Strategies for End-to-End Web Apps Testing

Edit

Develop

QA

Coding style/lint, semantic outline, autocomplete, API usage, refactoring, better syntax

Test framework, remote control, precommit check, automatic reload, fast smoke testing, preflight metrics

Comprehensive browser driver, code coverage, performance baseline, execution tracking

Page 46: Strategies for End-to-End Web Apps Testing

To boldly analyze what no man has analyzed before...

Page 47: Strategies for End-to-End Web Apps Testing

Thank You

[email protected]

@AriyaHidayat

ariya.ofilabs.com