Slide 1

Slide 1 text

Testin your Backbone from the outside-in Jim Newbery @froots101

Slide 2

Slide 2 text

JavaScript 2004 LOL DHTML MENUS!

Slide 3

Slide 3 text

JavaScript 2012 ZOMG CALLBACKS! REALTIME! NETWORKING! MEMORY! MOBILE!

Slide 4

Slide 4 text

Backbone.js — TDD

Slide 5

Slide 5 text

• decoupled units • few dependencies • conventions

Slide 6

Slide 6 text

The TDD cycle

Slide 7

Slide 7 text

RED failin test GREEN test passes REFACTOR

Slide 8

Slide 8 text

How do we know when we’re finished?

Slide 9

Slide 9 text

Behaviour-driven development

Slide 10

Slide 10 text

Focus on • business value • user oals • communication

Slide 11

Slide 11 text

Outside-in approach • User oals • Scenarios • Behavioural interactions

Slide 12

Slide 12 text

The BDD Cycle

Slide 13

Slide 13 text

RED GREEN RE- FACTOR Unit RED failin test GREEN test passes REFACTOR Acceptance

Slide 14

Slide 14 text

Tools

Slide 15

Slide 15 text

Automated Acceptance Testin is a pain in the arse

Slide 16

Slide 16 text

Acceptance testin pains • Slow • Non-deterministic • Difficult to debu • Incomplete browser features

Slide 17

Slide 17 text

“Write as few as possible, but no fewer” — Brandon Keepers

Slide 18

Slide 18 text

Can I write my acceptance tests in JavaScript?

Slide 19

Slide 19 text

JS acceptance test options • Cucumber.js & Zombie • CasperJS & PhantomJS

Slide 20

Slide 20 text

Example Snippetron: a revolutionary code snippet mana er

Slide 21

Slide 21 text

A user story As an efficient developer, I would like to save a snippet, So that I can retrieve it later

Slide 22

Slide 22 text

A BDD scenario Given I have no snippets yet When I fill out and submit the snippet form Then I should see a messa e sayin my save was successful

Slide 23

Slide 23 text

Snippetron Create a snippet Snippet title My first snippet Snippet contents var  a  =  5  *  5; Create snippet

Slide 24

Slide 24 text

Snippetron Create a snippet Snippet title Snippet contents Create snippet Snippet “My first snippet” saved!

Slide 25

Slide 25 text

CasperJS A scriptin and navi ation utility for PhantomJS

Slide 26

Slide 26 text

Some CasperJS assertions assert() assertEquals() assertExists() assertHttpStatus() assertMatch() assertResourceExists() assertTitle() assertUrlMatch() assertEval()

Slide 27

Slide 27 text

Useful acceptance testin features back()  &  forward() click() debugHTML() fill() getGlobal() mouseEvent() userAgent() viewport() capture() waitForSelector() waitForResource() waitUntilVisible()

Slide 28

Slide 28 text

var  baseUrl  =  "http://localhost:3000"; casper.test.comment("Scenario:  Create  a  snippet"); casper.test.comment("Given  I  am  on  the  home   page"); casper.start(baseUrl,  function()  {    this.test.comment("When  I  fill  out  the  form");    this.fill("form.create-­‐snippet",  {        "title":  "Alert  example",        "content":  "alert('Hello  World!');"    });    this.test.comment("And  I  submit  the  form");    this.click("input[type='submit']"); }); ...

Slide 29

Slide 29 text

... casper.test.comment("Then  I  should  see  a  message"); casper.waitUntilVisible(".message",  function()  {    this.test.assertTextExists("Snippet  'Alert  example'  saved!"); },  function()  {    this.debugHTML();    this.test.fail("Create  snippet  message  timed  out"); },  3000); casper.run(function()  {    this.test.done(); });

Slide 30

Slide 30 text

CasperJS test output d1

Slide 31

Slide 31 text

Cucumber.js Pure JS port of the popular BDD story runner

Slide 32

Slide 32 text

Cucumber.js feature Feature:  Saving  a  snippet    As  an  efficient  developer    I  would  like  to  save  a  snippet    So  that  I  can  retrieve  it  later

Slide 33

Slide 33 text

Cucumber.js scenario Scenario:  Successful  save    Given  I  am  on  the  home  page    When  I  enter  "My  Snippet"  in  the  "Snippet  title"  field    And  I  enter  "Snippet  content"  in  the  "Snippet  content"  field    And  I  click  the  "Create  snippet"  button    Then  I  should  see  a  message  with  "Snippet  'My  Snippet'  saved!"

Slide 34

Slide 34 text

Cucumber.js step definitions this.Given(/^I  am  on  the  home  page$/,  function (callback)  {    this.visit("/",  callback); }); this.When(/^I  enter  "([^"]*)"  in  the  "([^"]*)"  field$/,   function(val,  fieldSelector,  callback)  {    this.browser.fill(fieldSelector,  val,  callback); });

Slide 35

Slide 35 text

Cucumber.js step definitions this.Then(/^I  should  see  a  message  with  "([^"]*)"$/,    function(messageText,  callback)  {    if  (this.browser.text(".message")  !==  messageText)  {        callback.fail(new  Error("Expected  to  see  a  message  with   text  '"  +  messageText  +  '"'));    }  else  {        callback();    } });

Slide 36

Slide 36 text

A failin Cucumber.js scenario

Slide 37

Slide 37 text

Time for a unit test RED GREEN RE- FACTOR Unit RED failin test Acceptance

Slide 38

Slide 38 text

RED failin test Acceptance GREEN RE- FACTOR GREEN test passes REFACTOR RED Unit

Slide 39

Slide 39 text

What unit to work on? A failin acceptance test can provide a clue CasperJS Cucumber.js

Slide 40

Slide 40 text

Plannin & Communication submit handler Form view Snippet model creates + saves Server POST request show messa e success handler response submit user

Slide 41

Slide 41 text

Unit testin

Slide 42

Slide 42 text

Many many tools • QUnit • Jasmine BDD • Mocha • Node.js test frameworks • Countless others

Slide 43

Slide 43 text

BusterJS a JavaScript testin toolkit

Slide 44

Slide 44 text

BusterJS features • Multiple-browser testin • TDD or BDD syntax styles • inte rated test doubles: spies, stubs & mocks

Slide 45

Slide 45 text

Why use test doubles? • Isolate subject of test • Ensure determinism • Protect from slow, inconsistent or incomplete dependencies

Slide 46

Slide 46 text

SinonJS – a BDDer’s best friend • Send objects on spyin missions • Stub method responses • Stand-ins for server interactions • Manipulate space-time* *Well, time

Slide 47

Slide 47 text

Example Savin a model

Slide 48

Slide 48 text

describe("Snippet.Model",  function()  {    describe("when  saved",  function()  {        beforeEach(function()  {            this.server  =  sinon.fakeServer.create();                        this.attrs  =  {                title:  "My  Snippet",                content:  "My  Snippet  content"            };            this.subject  =  new  Snippet.Model();            this.subject.save(this.attrs);        });        afterEach(function()  {            this.server.restore();        }); ...

Slide 49

Slide 49 text

...        it("makes  a  request  to  the  root",  function()  {            expect(this.server.requests[0].url).toEqual("/");        });        it("submits  the  correct  body",  function()  {            var  body  =  JSON.parse(this.server.requests [0].requestBody);            expect(body.title).toEqual(this.attrs.title);            expect(body.content).toEqual(this.attrs.content);        });    }); });

Slide 50

Slide 50 text

Browser slavery

Slide 51

Slide 51 text

The BusterJS test runner

Slide 52

Slide 52 text

Fulfillin the example

Slide 53

Slide 53 text

var  Snippet  =  {    Model:  Backbone.Model.extend({  urlRoot:  "/"  }), };

Slide 54

Slide 54 text

The joy of reen - BusterJS

Slide 55

Slide 55 text

… a few cycles later …

Slide 56

Slide 56 text

var  Snippet  =  {    Model:  Backbone.Model.extend({  urlRoot:  "/"  }),    Views:  {        Form:  Backbone.View.extend({            events:  {                "submit":  "create"            },            create:  function(ev)  {                ev.preventDefault();                this.model  =  new  Snippet.Model();                this.model.save({                    "title":  this.$("[name='title']").val(),                    "content":  this.$("[name='content']").val()                });            }        })    } };

Slide 57

Slide 57 text

The joy of reen - BusterJS

Slide 58

Slide 58 text

The joy of reen – CasperJS

Slide 59

Slide 59 text

The joy of reen-ish – Cucumber.js

Slide 60

Slide 60 text

The joy of reen

Slide 61

Slide 61 text

Hold your horses

Slide 62

Slide 62 text

RED Unit Refactorin is important GREEN GREEN test passes RE- FACTOR REFACTOR

Slide 63

Slide 63 text

What’s next? • Next acceptance test? • Exceptional circumstances • e. . validation, double submit • Exploratory testin

Slide 64

Slide 64 text

More techniques: tinnedfruit.com cjohansen.no addyosmani.com

Slide 65

Slide 65 text

This is just the start

Slide 66

Slide 66 text

Thanks! @froots101 Fork it! https:// ithub.com/froots/snippetron