29
JavaScript unit testing with

JavaScript Unit Testing with Jasmine

  • Upload
    rsim

  • View
    2.306

  • Download
    0

Embed Size (px)

DESCRIPTION

Presentation in javascript.lv meetup

Citation preview

Page 1: JavaScript Unit Testing with Jasmine

JavaScriptunit testing

with

Page 2: JavaScript Unit Testing with Jasmine

Raimonds Simanovskis github.com/rsim

@rsim

Page 3: JavaScript Unit Testing with Jasmine

The easiest Business Intelligence tool on the Web

Page 4: JavaScript Unit Testing with Jasmine

Using threadsin Ruby applications

Page 5: JavaScript Unit Testing with Jasmine

Using threadsin JavaScript applications

Page 6: JavaScript Unit Testing with Jasmine

You can’t :)

Page 7: JavaScript Unit Testing with Jasmine

JavaScriptunit testing

with

Page 8: JavaScript Unit Testing with Jasmine

RSpec-like testing for JavaScript

Page 9: JavaScript Unit Testing with Jasmine

Syntaxdescribe("A suite", function() { it("contains spec with an expectation", function() { expect(true).toBe(true); });});

describe("A suite is just a function", function() { var a;

it("and so is a spec", function() { a = true;

expect(a).toBe(true); });});

Page 10: JavaScript Unit Testing with Jasmine

Matchers

describe("The 'toBe' matcher compares with ===", function() {

it("and has a positive case ", function() { expect(true).toBe(true); });

it("and can have a negative case", function() { expect(false).not.toBe(true); });

});

Page 11: JavaScript Unit Testing with Jasmine

Included matchers

toBetoEqualtoMatchtoBeDefinedtoBeUndefinedtoBeNulltoBeTruthytoBeFalsy

toContaintoBeLessThantoBeGreaterThantoBeCloseTotoThrow

Page 12: JavaScript Unit Testing with Jasmine

Setup & teardowndescribe("A spec (with setup and tear-down)", function() { var foo;

beforeEach(function() { foo = 0; foo += 1; });

afterEach(function() { foo = 0; });

it("is just a function, so it can contain any code", function() { expect(foo).toEqual(1); });

it("can have more than one expectation", function() { expect(foo).toEqual(1); expect(true).toEqual(true); });});

Page 13: JavaScript Unit Testing with Jasmine

Nestingdescribe("A spec", function() { var foo; beforeEach(function() { foo = 0; foo += 1; }); afterEach(function() { foo = 0; }); it("is just a function, so it can contain any code", function() { expect(foo).toEqual(1); }); it("can have more than one expectation", function() { expect(foo).toEqual(1); expect(true).toEqual(true); }); describe("nested inside a second describe", function() { var bar; beforeEach(function() { bar = 1; }); it("can reference both scopes as needed ", function() { expect(foo).toEqual(bar); }); });});

Page 14: JavaScript Unit Testing with Jasmine

Disabling

xdescribe("A spec", function() { var foo;

beforeEach(function() { foo = 0; foo += 1; });

xit("is just a function, so it can contain any code", function() { expect(foo).toEqual(1); });});

Page 15: JavaScript Unit Testing with Jasmine

Spiesdescribe("A spy", function() { var foo, bar = null; beforeEach(function() { foo = { setBar: function(value) { bar = value; } }; spyOn(foo, 'setBar'); foo.setBar(123); foo.setBar(456, 'another param'); }); it("tracks that the spy was called", function() { expect(foo.setBar).toHaveBeenCalled(); }); it("tracks its number of calls", function() { expect(foo.setBar.calls.length).toEqual(2); }); it("tracks all the arguments of its calls", function() { expect(foo.setBar).toHaveBeenCalledWith(123); expect(foo.setBar).toHaveBeenCalledWith(456, 'another param'); }); it("allows access to the most recent call", function() { expect(foo.setBar.mostRecentCall.args[0]).toEqual(456); }); it("allows access to other calls", function() { expect(foo.setBar.calls[0].args[0]).toEqual(123); }); it("stops all execution on a function", function() { expect(bar).toBeNull(); });});

Page 16: JavaScript Unit Testing with Jasmine

andReturndescribe("A spy, when faking a return value", function() { var foo, bar, fetchedBar; beforeEach(function() { foo = { setBar: function(value) { bar = value; }, getBar: function() { return bar; } }; spyOn(foo, 'getBar').andReturn(745); foo.setBar(123); fetchedBar = foo.getBar(); }); it("tracks that the spy was called", function() { expect(foo.getBar).toHaveBeenCalled(); }); it("should not effect other functions", function() { expect(bar).toEqual(123); }); it("when called returns the requested value", function() { expect(fetchedBar).toEqual(745); });});

Page 17: JavaScript Unit Testing with Jasmine

Async testsdescribe("Asynchronous specs", function() { var value, flag; it("should support async execution of test preparation and exepectations", function() { runs(function() { flag = false; value = 0; setTimeout(function() { flag = true; }, 500); }); waitsFor(function() { value++; return flag; }, "The Value should be incremented", 750); runs(function() { expect(value).toBeGreaterThan(0); }); });});

Page 18: JavaScript Unit Testing with Jasmine

Jasmine tests runner

Demo

Page 19: JavaScript Unit Testing with Jasmine

Works nicewith CoffeeScriptand Backbone.js

Page 20: JavaScript Unit Testing with Jasmine

Testing Backbone.js model

describe "Todo", -> todo = null ajaxCall = (param) -> jQuery.ajax.mostRecentCall.args[0][param]

beforeEach -> todo = new TodoApp.Todo todos = new TodoApp.TodoList [todo]

it "should initialize with empty content", -> expect(todo.get "content").toEqual "empty todo..."

it "should initialize as not done", -> expect(todo.get "done").toBeFalsy()

it "should save after toggle", -> spyOn jQuery, "ajax" todo.toggle() expect(ajaxCall "url").toEqual "/todos" expect(todo.get "done").toBeTruthy()

Page 21: JavaScript Unit Testing with Jasmine

and collection

describe "TodoList", -> attributes = [ content: "First" done: true , content: "Second" ] todos = null

beforeEach -> todos = new TodoApp.TodoList attributes it "should return done todos", -> expect(_.invoke todos.done(), "toJSON").toEqual [attributes[0]]

it "should return remaining todos", -> expect(_.invoke todos.remaining(), "toJSON").toEqual [attributes[1]]

Page 22: JavaScript Unit Testing with Jasmine

jasmine-jquery

• a set of custom matchers for jQuery framework

• an API for handling HTML, CSS, and JSON fixtures in your specs

Page 23: JavaScript Unit Testing with Jasmine

expect($('<div id="some-id"></div>')).toBe('div#some-id')

expect($('<input type="checkbox" checked="checked"/>')).toBeChecked()

expect($('<div style="display: none; margin: 10px;"></div>')).toHaveCss({display: "none", margin: "10px"})

expect($('<option selected="selected"></option>')).toBeSelected()

expect($('<div><span class="some-class"></span></div>')).toContain('span.some-class')

expect($('<div class="some-class"></div>')).toHaveClass("some-class")

expect($('<div><span></span></div>')).toHaveHtml('<span></span>')

expect($('<div><ul></ul><h1>header</h1></div>')).toContainHtml('<ul></ul>')

expect($('<div>some text</div>')).toHaveText('some text')

expect($('<input type="text" value="some text"/>')).toHaveValue('some text')

expect('<input type='submit' disabled='disabled'/>').toBeDisabled()

expect($('<input type='text' />').focus()).toBeFocused()

Page 24: JavaScript Unit Testing with Jasmine

HTML fixtures

In myfixture.html file:

<div id="my-fixture">some complex content here</div>

Inside your test:

loadFixtures('myfixture.html');$('#my-fixture').myTestedPlugin();expect($('#my-fixture')).to...;

Page 25: JavaScript Unit Testing with Jasmine

jasmine-fixture// Let's say you want to write a Jasmine spec for some code// that needs to select elements from the DOM with jQuery:

$('#toddler .hidden.toy input[name="toyName"][value="cuddle bunny"]')

// In the good ol' days of manually crafting your HTML fixtures,// you'd have to append some raw HTML to the DOM like this:

beforeEach(function(){ $('<div id="toddler"><div class="hidden toy"><input name="toyName" value="cuddle bunny"></div></div>').appendTo('body');});

afterEach(function(){ $('#toddler').remove()});

// But jasmine-fixture's affix method lets you do this instead:

beforeEach(function(){ affix('#toddler .hidden.toy input[name="toyName"][value="cuddle bunny"]')});

Page 26: JavaScript Unit Testing with Jasmine

jasmine-givendescribe("assigning stuff to this", function() { Given(function() { this.number = 24; }); Given(function() { this.number++; }); When(function() { this.number *= 2; }); Then(function() { return this.number === 50; }); // or Then(function() { expect(this.number).toBe(50) });});

describe("assigning stuff to variables", function() { var subject; Given(function() { subject = []; }); When(function() { subject.push('foo'); }); Then(function() { return subject.length === 1; }); // or Then(function() { expect(subject.length).toBe(1); });});

Page 27: JavaScript Unit Testing with Jasmine

jasmine-givendescribe "assigning stuff to this", -> Given -> @number = 24 Given -> @number++ When -> @number *= 2 Then -> @number == 50 # or Then -> expect(@number).toBe(50)

describe "assigning stuff to variables", -> subject=null Given -> subject = [] When -> subject.push('foo') Then -> subject.length == 1 # or Then -> expect(subject.length).toBe(1)

Page 28: JavaScript Unit Testing with Jasmine

jasmine-stealthdescribe("multiple stubbings", function() { var someSpy; beforeEach(function() { someSpy = jasmine.createSpy(); someSpy.when("pirate", { booty: ["jewels",jasmine.any(String)]}).thenReturn("argh!"); someSpy.when("panda",1).thenReturn("sad"); });

it("stubs the first accurately", function() { expect(someSpy("pirate",{ booty: ["jewels","coins"]})).toBe("argh!"); });

it("stubs the second too", function() { expect(someSpy("panda",1)).toBe("sad"); });

it("doesn't return anything when a stubbing isn't satisfied",function(){ expect(someSpy("anything else at all")).not.toBeDefined(); });});

Page 29: JavaScript Unit Testing with Jasmine

References

https://github.com/rsim/backbone_coffeescript_demo

http://pivotal.github.io/jasmine/

https://github.com/rsim/rpn_calculator

http://searls.testdouble.com/posts/2013-03-21-jasmine-tactics-screencast.html

http://vimeo.com/53655205