JavaScript Unit Testing with Jasmine

3,647 views

Published on

Presentation in javascript.lv meetup

Published in: Technology

JavaScript Unit Testing with Jasmine

  1. 1. JavaScriptunit testing with
  2. 2. @rsim github.com/rsimRaimonds Simanovskis
  3. 3. The easiest Business Intelligence tool on the Web
  4. 4. Using threadsin Ruby applications
  5. 5. Using threadsin JavaScript applications
  6. 6. You can’t :)
  7. 7. JavaScriptunit testing with
  8. 8. RSpec-like testing for JavaScript
  9. 9. 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); });});
  10. 10. Matchersdescribe("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); });});
  11. 11. Included matchers toBe toContain toEqual toBeLessThan toMatch toBeGreaterThan toBeDefined toBeCloseTo toBeUndefined toThrow toBeNull toBeTruthy toBeFalsy
  12. 12. 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); });});
  13. 13. describe("A spec", function() { var foo; beforeEach(function() { Nesting 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); }); });});
  14. 14. Disablingxdescribe("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); });});
  15. 15. describe("A spy", function() { Spies 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(); });});
  16. 16. describe("A spy, when faking a return value", function() { var foo, bar, fetchedBar; beforeEach(function() { andReturn 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); });});
  17. 17. Async testsdescribe("Asynchronous specs", function() { var value, flag; it("should support async execution of test preparation andexepectations", 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); }); });});
  18. 18. Jasmine tests runner Demo
  19. 19. Works nicewith CoffeeScriptand Backbone.js
  20. 20. Testing Backbone.js modeldescribe "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()
  21. 21. and collectiondescribe "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]]
  22. 22. jasmine-jquery• a set of custom matchers for jQuery framework• an API for handling HTML, CSS, and JSON fixtures in your specs
  23. 23. 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(sometext)expect(<input type=submit disabled=disabled/>).toBeDisabled()expect($(<input type=text />).focus()).toBeFocused()
  24. 24. HTML fixturesIn 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...;
  25. 25. jasmine-fixture// Lets 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,// youd 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-fixtures affix method lets you do this instead:beforeEach(function(){ affix(#toddler .hidden.toy input[name="toyName"][value="cuddle bunny"])});
  26. 26. 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); });});
  27. 27. 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)
  28. 28. 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("doesnt return anything when a stubbing isnt satisfied",function(){ expect(someSpy("anything else at all")).not.toBeDefined(); });});
  29. 29. References http://pivotal.github.io/jasmine/ http://searls.testdouble.com/posts/2013-03-21- jasmine-tactics-screencast.htmlhttps://github.com/rsim/backbone_coffeescript_demo https://github.com/rsim/rpn_calculator http://vimeo.com/53655205

×