test and behavior driven development in javascript

113
Test and Behavior Driven Development in JavaScript Steven Parkes [email protected]

Upload: others

Post on 12-Sep-2021

3 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Test and Behavior Driven Development in JavaScript

Test and Behavior Driven Development

inJavaScript

Steven [email protected]

Page 2: Test and Behavior Driven Development in JavaScript

“JavaScript” means Different things to Different People

Page 3: Test and Behavior Driven Development in JavaScript

<FORM NAME=‘FORM’><TABLE BORDER CELLPADDING=3><TR><TD><NOBR>radius: <INPUT NAME="Circle_radius" SIZE=4></NOBR></TD><TD><INPUT TYPE=BUTTON onclick="document.FORM.submit();" VALUE="calculate"></TD><TD ALIGN=RIGHT BGCOLOR="#AACCFF"><NOBR>circumference: <INPUT NAME="Circle_circumference" SIZE=9></NOBR><BR><NOBR>area: <INPUT NAME="Circle_area" SIZE=9></NOBR></TD></TR></TABLE></FORM>

Page 4: Test and Behavior Driven Development in JavaScript

var http = require('http');http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World\n');}).listen(8124, "127.0.0.1");console.log('Server running at http://127.0.0.1:8124/');

Page 5: Test and Behavior Driven Development in JavaScript
Page 6: Test and Behavior Driven Development in JavaScript

Canvas

Offline Applications

Local Storage

Video

XMLHttpRequest

SVG

“HTML5”

Page 7: Test and Behavior Driven Development in JavaScript

ChessFlock

Page 8: Test and Behavior Driven Development in JavaScript

XMPP

Page 9: Test and Behavior Driven Development in JavaScript

ejabberd

xmppxmpp

xmpp

Page 10: Test and Behavior Driven Development in JavaScript

ejabberd

http

kibosh

http

httpkibosh kibosh

Page 11: Test and Behavior Driven Development in JavaScript

ejabberd: XMPP server written in Erlang

kibosh: XMPP BOSH connection manager written in Ruby

strophejs: XMPP BOSH clientwritten in JavaScript

dramatis: actor librarywritten in JavaScript/Ruby/Python

chessflock: chess client/serverwritten in JavaScript/HTML/SVG

Server

Client

Page 12: Test and Behavior Driven Development in JavaScript

Caveats

Page 13: Test and Behavior Driven Development in JavaScript

Incomplete

Page 14: Test and Behavior Driven Development in JavaScript

Low test coverage

Page 15: Test and Behavior Driven Development in JavaScript

Egregiousstupidity

Page 16: Test and Behavior Driven Development in JavaScript

Dramatistestbed

Page 17: Test and Behavior Driven Development in JavaScript

“throw one away”

Page 18: Test and Behavior Driven Development in JavaScript

Test Driven Development

Page 19: Test and Behavior Driven Development in JavaScript

s/Test/Behavior/

Page 20: Test and Behavior Driven Development in JavaScript

Test Driven Development

Page 21: Test and Behavior Driven Development in JavaScript

Test Driven Development

Page 22: Test and Behavior Driven Development in JavaScript

Test Driven Development

Page 23: Test and Behavior Driven Development in JavaScript

Test Driven Development

Page 24: Test and Behavior Driven Development in JavaScript

Write the tests first

Page 25: Test and Behavior Driven Development in JavaScript

Red Green Refactor

Page 26: Test and Behavior Driven Development in JavaScript

Flavors of tests

Page 27: Test and Behavior Driven Development in JavaScript

Unit

Page 28: Test and Behavior Driven Development in JavaScript

Irreducible

Page 29: Test and Behavior Driven Development in JavaScript

Monolingual

Page 30: Test and Behavior Driven Development in JavaScript

Integration

Multiple units

Maybe multiple languages

Page 31: Test and Behavior Driven Development in JavaScript

System

Page 32: Test and Behavior Driven Development in JavaScript

UnitMonolingual (JavaScript) Integration

Developer focused

Page 33: Test and Behavior Driven Development in JavaScript

What makes JavaScript so special?

Page 34: Test and Behavior Driven Development in JavaScript

Standard Library

or lack thereof

Page 35: Test and Behavior Driven Development in JavaScript

ObjectArray

FunctionDateStringRegex

Page 36: Test and Behavior Driven Development in JavaScript

Asynchronousno waitno sleep

not threads

Page 37: Test and Behavior Driven Development in JavaScript

Asynchronousno waitno sleep

no threads

setTimeout

Page 38: Test and Behavior Driven Development in JavaScript

Asynchronousno waitno sleep

no threads

window.setTimeout

Page 39: Test and Behavior Driven Development in JavaScript

Asynchronousno waitno sleep

no threads

window.setTimeout

Page 40: Test and Behavior Driven Development in JavaScript

Asynchronousno waitno sleep

no Threads

window.setTimeout

I/O

Page 41: Test and Behavior Driven Development in JavaScript

Asynchronousno waitno sleep

no threads

window.setTimeout

I/O

Packaging

Page 42: Test and Behavior Driven Development in JavaScript

Asynchronousno waitno sleep

no threads

window.setTimeout

I/O

Packaging

SpiderMonkey v8 SquirrelFish Rhino

Page 43: Test and Behavior Driven Development in JavaScript

ObjectArray

FunctionDateStringRegex

Need more than this to run tests

Page 44: Test and Behavior Driven Development in JavaScript

Beyond ES5

Page 45: Test and Behavior Driven Development in JavaScript

CommonJS

Page 46: Test and Behavior Driven Development in JavaScript

“HTML5”

Page 47: Test and Behavior Driven Development in JavaScript

<HTML> <HEAD> <TITLE></TITLE> </HEAD> <BODY> </BODY></HTML>

Page 48: Test and Behavior Driven Development in JavaScript

window

Page 49: Test and Behavior Driven Development in JavaScript

window.setTimeout

Page 50: Test and Behavior Driven Development in JavaScript

window.setTimeout

Timers / events / event loops

Page 51: Test and Behavior Driven Development in JavaScript

window.XMLHttpRequest

Page 52: Test and Behavior Driven Development in JavaScript

HTML5 implementations

Page 53: Test and Behavior Driven Development in JavaScript

Browsers, of coursebut also ...

Page 54: Test and Behavior Driven Development in JavaScript

HTMLUnit

Java

Rhino

Page 55: Test and Behavior Driven Development in JavaScript

Env.js

“mostly” JavaScript

Rhino/SpiderMonkey

Page 56: Test and Behavior Driven Development in JavaScript

JavaScript TDD/BDD vs ...

Page 57: Test and Behavior Driven Development in JavaScript

Dynamically typed

Loose scoping

No protection levels

Page 58: Test and Behavior Driven Development in JavaScript

Highly asynchronousLots of callbacks

Lots of async callbacks

Page 59: Test and Behavior Driven Development in JavaScript

JavaScript TDD and BDD Frameworks

Page 60: Test and Behavior Driven Development in JavaScript

But first ...

Page 61: Test and Behavior Driven Development in JavaScript

JSLint

Page 62: Test and Behavior Driven Development in JavaScript

JavaScript TDD: qunit

Page 63: Test and Behavior Driven Development in JavaScript

test("module without setup/teardown (default)", function() { expect(1); ok(true);});

Page 64: Test and Behavior Driven Development in JavaScript

test("module without setup/teardown (default)", function() { expect(1); ok(true);});

ok()equals()same()

Page 65: Test and Behavior Driven Development in JavaScript

test("module without setup/teardown (default)", function() { expect(1); ok(true);});

ok()equals()same()

module()setup()teardown()

Page 66: Test and Behavior Driven Development in JavaScript

test("runnable callbacks are run later with timeout of 0", function() { expect(2); var occurred = 0; setTimeout(function(){         occurred = Date.now();     }, 0); ok( occurred === 0, "Timeout callback was not executed immediately" );    setTimeout(function(){      ok( occurred !== 0, "Timeout callback executed" );      start();    },100);    stop();});

Asynch test:test is not complete at the end of the function body

Page 67: Test and Behavior Driven Development in JavaScript

test("runnable callbacks are run later with timeout of 0", function() { expect(2); var occurred = 0; setTimeout(function(){         occurred = Date.now();     }, 0); ok( occurred === 0, "Timeout callback was not executed immediately" );    setTimeout(function(){      ok( occurred !== 0, "Timeout callback executed" );      start();    },100);    stop();});

stop()

Page 68: Test and Behavior Driven Development in JavaScript

test("runnable callbacks are run later with timeout of 0", function() { expect(2); var occurred = 0; setTimeout(function(){         occurred = Date.now();     }, 0); ok( occurred === 0, "Timeout callback was not executed immediately" );    setTimeout(function(){      ok( occurred !== 0, "Timeout callback executed" );      start();    },100);    stop();});

incomplete()

Page 69: Test and Behavior Driven Development in JavaScript

test("runnable callbacks are run later with timeout of 0", function() { expect(2); var occurred = 0; setTimeout(function(){         occurred = Date.now();     }, 0); ok( occurred === 0, "Timeout callback was not executed immediately" );    setTimeout(function(){      ok( occurred !== 0, "Timeout callback executed" );      start();    },100);    stop();});

start()

Page 70: Test and Behavior Driven Development in JavaScript

test("runnable callbacks are run later with timeout of 0", function() { expect(2); var occurred = 0; setTimeout(function(){         occurred = Date.now();     }, 0); ok( occurred === 0, "Timeout callback was not executed immediately" );    setTimeout(function(){      ok( occurred !== 0, "Timeout callback executed" );      start();    },100);    stop();});

complete()

Page 71: Test and Behavior Driven Development in JavaScript

test("runnable callbacks are run later with timeout of 0", function() { expect(2); var occurred = 0; setTimeout(function(){         occurred = Date.now();     }, 0); ok( occurred === 0, "Timeout callback was not executed immediately" );    setTimeout(function(){      ok( occurred !== 0, "Timeout callback executed" );      start();    },100);    stop();});

expect(n)

Page 72: Test and Behavior Driven Development in JavaScript

What if start() is never called?

Page 73: Test and Behavior Driven Development in JavaScript

JavaScript BDD: Jasmine

Page 74: Test and Behavior Driven Development in JavaScript

it("should return the game to the players",function(){          var tom = { player_name: function(){ return "tom"; }};          var jerry = { player_name: function(){ return "tom"; }};          var toms_game;          var jerrys_game;          this.server.join(tom, function(game) {            toms_game = game;            if (jerrys_game) {              expect(toms_game).toBe(jerrys_game);              complete();            }          });          this.server.join(jerry, function(game) {            jerrys_game = game;            if (toms_game) {              expect(toms_game).toBe(jerrys_game);              complete();            }          });          incomplete();        });

it(...)expect(...).toSomething()

complete/incomplete(...)

Page 75: Test and Behavior Driven Development in JavaScript

Ready, Set, Go ...

Page 76: Test and Behavior Driven Development in JavaScript

Uh ...

Page 77: Test and Behavior Driven Development in JavaScript

Fixtures

Page 78: Test and Behavior Driven Development in JavaScript

<!DOCTYPE html><html><head> <title>QUnit Test Suite</title> <link rel="stylesheet" href="../qunit/qunit.css" type="text/css" media="screen"> <script type="text/javascript" src="../qunit/qunit.js"></script> <script type="text/javascript" src="test.js"></script> <script type="text/javascript" src="same.js"></script></head><body> <h1 id="qunit-header">QUnit Test Suite</h1> <h2 id="qunit-banner"></h2> <div id="qunit-testrunner-toolbar"></div> <h2 id="qunit-userAgent"></h2> <ol id="qunit-tests"></ol></body></html>

Page 79: Test and Behavior Driven Development in JavaScript

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head>  <title>Jasmine Test Runner</title>

  <script type="text/javascript">    // yes, really keep this here to keep us honest, but only for jasmine's own runner! [xw]    undefined = "diz be undefined yo";  </script>

  <script type="text/javascript" src="../src/base.js"></script>  <script type="text/javascript" src="../src/util.js"></script>  <script type="text/javascript" src="../src/Env.js"></script>  <script type="text/javascript" src="../src/Reporter.js"></script>  <script type="text/javascript" src="../src/Block.js"></script>

  <script type="text/javascript" src="../src/JsApiReporter.js"></script>  <script type="text/javascript" src="../src/Matchers.js"></script>  <script type="text/javascript" src="../src/mock-timeout.js"></script>  <script type="text/javascript" src="../src/MultiReporter.js"></script>  <script type="text/javascript" src="../src/NestedResults.js"></script>  <script type="text/javascript" src="../src/PrettyPrinter.js"></script>  <script type="text/javascript" src="../src/Queue.js"></script>  <script type="text/javascript" src="../src/Runner.js"></script>  <script type="text/javascript" src="../src/Spec.js"></script>  <script type="text/javascript" src="../src/Suite.js"></script>  <script type="text/javascript" src="../src/WaitsBlock.js"></script>  <script type="text/javascript" src="../src/WaitsForBlock.js"></script>

  <script type="text/javascript" src="../src/html/TrivialReporter.js"></script>

  <script type="text/javascript" src="suites/BaseSpec.js"></script>  <script type="text/javascript" src="suites/CustomMatchersSpec.js"></script>  <script type="text/javascript" src="suites/EnvSpec.js"></script>  <script type="text/javascript" src="suites/ExceptionsSpec.js"></script>  <script type="text/javascript" src="suites/JsApiReporterSpec.js"></script>  <script type="text/javascript" src="suites/MatchersSpec.js"></script>  <script type="text/javascript" src="suites/MockClockSpec.js"></script>  <script type="text/javascript" src="suites/MultiReporterSpec.js"></script>  <script type="text/javascript" src="suites/NestedResultsSpec.js"></script>  <script type="text/javascript" src="suites/PrettyPrintSpec.js"></script>  <script type="text/javascript" src="suites/ReporterSpec.js"></script>  <script type="text/javascript" src="suites/RunnerSpec.js"></script>  <script type="text/javascript" src="suites/QueueSpec.js"></script>  <script type="text/javascript" src="suites/SpecSpec.js"></script>  <script type="text/javascript" src="suites/SpecRunningSpec.js"></script>  <script type="text/javascript" src="suites/SpySpec.js"></script>  <script type="text/javascript" src="suites/SuiteSpec.js"></script>  <script type="text/javascript" src="suites/TrivialReporterSpec.js"></script>  <script type="text/javascript" src="suites/WaitsForBlockSpec.js"></script>

  <script type="text/javascript">    (function() {      var jasmineEnv = jasmine.getEnv();      jasmineEnv.updateInterval = 1000;

      var trivialReporter = new jasmine.TrivialReporter();

      jasmineEnv.addReporter(trivialReporter);

      jasmineEnv.specFilter = function(spec) {        return trivialReporter.specFilter(spec);      };

      window.onload = function() {        jasmineEnv.execute();      };    })();  </script>

  <link href="../src/html/jasmine.css" rel="stylesheet"/></head>

<body></body></html>

Page 80: Test and Behavior Driven Development in JavaScript

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head>  <title>Jasmine Test Runner</title>

  <script type="text/javascript">    // yes, really keep this here to keep us honest, but only for jasmine's own runner! [xw]    undefined = "diz be undefined yo";  </script>

  <script type="text/javascript" src="../src/base.js"></script>  <script type="text/javascript" src="../src/util.js"></script>  <script type="text/javascript" src="../src/Env.js"></script>  <script type="text/javascript" src="../src/Reporter.js"></script>  <script type="text/javascript" src="../src/Block.js"></script>

  <script type="text/javascript" src="../src/JsApiReporter.js"></script>  <script type="text/javascript" src="../src/Matchers.js"></script>  <script type="text/javascript" src="../src/mock-timeout.js"></script>  <script type="text/javascript" src="../src/MultiReporter.js"></script>  <script type="text/javascript" src="../src/NestedResults.js"></script>  <script type="text/javascript" src="../src/PrettyPrinter.js"></script>  <script type="text/javascript" src="../src/Queue.js"></script>  <script type="text/javascript" src="../src/Runner.js"></script>  <script type="text/javascript" src="../src/Spec.js"></script>  <script type="text/javascript" src="../src/Suite.js"></script>  <script type="text/javascript" src="../src/WaitsBlock.js"></script>  <script type="text/javascript" src="../src/WaitsForBlock.js"></script>

  <script type="text/javascript" src="../src/html/TrivialReporter.js"></script>

  <script type="text/javascript" src="suites/BaseSpec.js"></script>  <script type="text/javascript" src="suites/CustomMatchersSpec.js"></script>  <script type="text/javascript" src="suites/EnvSpec.js"></script>  <script type="text/javascript" src="suites/ExceptionsSpec.js"></script>  <script type="text/javascript" src="suites/JsApiReporterSpec.js"></script>  <script type="text/javascript" src="suites/MatchersSpec.js"></script>  <script type="text/javascript" src="suites/MockClockSpec.js"></script>  <script type="text/javascript" src="suites/MultiReporterSpec.js"></script>  <script type="text/javascript" src="suites/NestedResultsSpec.js"></script>  <script type="text/javascript" src="suites/PrettyPrintSpec.js"></script>  <script type="text/javascript" src="suites/ReporterSpec.js"></script>  <script type="text/javascript" src="suites/RunnerSpec.js"></script>  <script type="text/javascript" src="suites/QueueSpec.js"></script>  <script type="text/javascript" src="suites/SpecSpec.js"></script>  <script type="text/javascript" src="suites/SpecRunningSpec.js"></script>  <script type="text/javascript" src="suites/SpySpec.js"></script>  <script type="text/javascript" src="suites/SuiteSpec.js"></script>  <script type="text/javascript" src="suites/TrivialReporterSpec.js"></script>  <script type="text/javascript" src="suites/WaitsForBlockSpec.js"></script>

  <script type="text/javascript">    (function() {      var jasmineEnv = jasmine.getEnv();      jasmineEnv.updateInterval = 1000;

      var trivialReporter = new jasmine.TrivialReporter();

      jasmineEnv.addReporter(trivialReporter);

      jasmineEnv.specFilter = function(spec) {        return trivialReporter.specFilter(spec);      };

      window.onload = function() {        jasmineEnv.execute();      };    })();  </script>

  <link href="../src/html/jasmine.css" rel="stylesheet"/></head>

<body></body></html>

Page 81: Test and Behavior Driven Development in JavaScript

Test Runners :What, Where, How, When, Why

Page 82: Test and Behavior Driven Development in JavaScript

Test Runners :What, Where, How, When

Page 83: Test and Behavior Driven Development in JavaScript

Without tests, code won’t work

Page 84: Test and Behavior Driven Development in JavaScript

Without tests, code won’t work

If writing tests is hard, they won’t get written

Page 85: Test and Behavior Driven Development in JavaScript

Without tests, code won’t work

If writing tests is hard, they won’t get written

If running tests is had, they won’t get run

Page 86: Test and Behavior Driven Development in JavaScript

Without tests, code won’t work

If writing tests is hard, they won’t get written

If running tests is had, they won’t get run

If tests don’t get run, they won’t get written

Page 87: Test and Behavior Driven Development in JavaScript

Without tests, code won’t work

If writing tests is hard, they won’t get written

If running tests is had, they won’t get run

If tests don’t get run, they won’t get written

Without tests, code won’t work

Page 88: Test and Behavior Driven Development in JavaScript

Make the simple things easyand the hard things possible

Page 89: Test and Behavior Driven Development in JavaScript

DOM vs non-DOM

Synch vs Asynch

Page 90: Test and Behavior Driven Development in JavaScript

Make the hard things possible

Page 91: Test and Behavior Driven Development in JavaScript

Make the hard things possibleand everything else equally hard

Page 92: Test and Behavior Driven Development in JavaScript

Write a testSwitch to browserLoad a test pageFind the/a failureSwitch to editorWrite codeSwitch to browserHit refreshFind the/a success

Lather, rinse, repeat

Page 93: Test and Behavior Driven Development in JavaScript

This sucks

Page 94: Test and Behavior Driven Development in JavaScript

Let me count the ways

Page 95: Test and Behavior Driven Development in JavaScript

Load what?

Page 96: Test and Behavior Driven Development in JavaScript

From where?

Page 97: Test and Behavior Driven Development in JavaScript

How, i.e., with what?

Page 98: Test and Behavior Driven Development in JavaScript

When?

Page 99: Test and Behavior Driven Development in JavaScript

What: pick your fixture(s)

Where: run some server somewhere

How: with the browser on my desktop(repeat as necessary)

When: when I feel like it

Page 100: Test and Behavior Driven Development in JavaScript

Did I mention this sucks?

Page 101: Test and Behavior Driven Development in JavaScript

What: I hate fixtures

Page 102: Test and Behavior Driven Development in JavaScript

They’re painful to setup

They don’t reflect the real world

Page 103: Test and Behavior Driven Development in JavaScript

In vitro

In situ

In vivo

Page 104: Test and Behavior Driven Development in JavaScript

Jazz: a test runner

Page 105: Test and Behavior Driven Development in JavaScript

Jazz

Supports Jasmine and qunit

Supports browsers (Chrome, Firefox)Supports env.js (Ruby/SpiderMonkey)

Can run fixture-less tests

Integrates with wake

Page 106: Test and Behavior Driven Development in JavaScript

Wake: make/rake + autotest/watchr

Page 107: Test and Behavior Driven Development in JavaScript

Save a file, run a test

Page 108: Test and Behavior Driven Development in JavaScript

Save a file, run tests

Page 109: Test and Behavior Driven Development in JavaScript

Understands dependences

Integrated with jazz/envjs

Page 110: Test and Behavior Driven Development in JavaScript

Records successes/failures

Re-executes: Changed files until success Failed tests until success All tests

Page 111: Test and Behavior Driven Development in JavaScript

Plugin Architecture

Matching source filesResult files

DependencesSuccess/failure

Page 112: Test and Behavior Driven Development in JavaScript

Plugins

haml/sassjazzjslintrbshellgraphics (inkscape, batik, rsvg)cache_manifest

Page 113: Test and Behavior Driven Development in JavaScript

qunit: http://github.com/jquery/qunitJasmine: http://github.com/pivotal/jasmine

my fork: http://github.com/smparkes/jasminejslintrb: http://github.com/smparkes/jslintrbjazz: http://github.com/smparkes/jazzwake: http://github.com/smparkes/wakettt: http://github.com/smparkes/tttchessflock: http://github.com/smparkes/chessflock