Unit testing JavaScript using Mocha and Node

10,511 views

Published on

Published in: Technology, Sports
0 Comments
7 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
10,511
On SlideShare
0
From Embeds
0
Number of Embeds
9
Actions
Shares
0
Downloads
88
Comments
0
Likes
7
Embeds 0
No embeds

No notes for slide

Unit testing JavaScript using Mocha and Node

  1. 1. Unit testing JavaScript using Mocha and Node.js
  2. 2. Josh Mock Senior JavaScript architect at Emma Twitter: Email: @JoshMock josh@joshmock.com
  3. 3. What is unit testing? Write code to test code Ensures code works as expected Granular, single-focus assertions Not a substitute for QA
  4. 4. Why unit test? Confidence Easier refactoring Less regression Less complexity TDD is fun!
  5. 5. What is Node.js?
  6. 6. Install Node.js node.js.org/download/ OS X (with Homebrew installed): brew install node
  7. 7. What is Mocha?
  8. 8. Install Mocha npm install -g mocha
  9. 9. Test some code! var Car = function () { this.make = "Honda"; this.model = "Civic"; };
  10. 10. var assert = require("assert"); describe("Car", function () { describe("constructor", function () { it("should default the car to be a Honda Civic"); }); describe("makeAndModel", function () { it("should return a string containing the make and model"); }); });
  11. 11. Run, tests, run mocha path/to/test/file.js
  12. 12. How to write good tests Test results, not internals One focus per test Testing DOM changes is bold
  13. 13. How to write testable code
  14. 14. Simple, single-purpose functions // bad var numbers = { list: [1, 2, 3], add: function (newNum) { this.list.push(newNum); this.list.sort(); } }; // good var numbers = { list: [1, 2, 3], add: function (newNum) { this.list.push(newNum); }, sort: function () { this.list.sort(); } };
  15. 15. Avoid tight coupling of components var numbers = { list: [1, 2, 3], add: function (newNum) { this.list.push(newNum); } }; // bad var math = { add: function () { var total = 0; for (var i = 0; i < numbers.list.length; i++) { total += numbers.list[i]; } return total; }, average: function () { return this.add() / numbers.list.length; } }; alert(math.average()); // good var math = { add: function (numList) { var total = 0; for (var i = 0; i < numList.length; i++) { total += numList[i]; } return total;
  16. 16. Separate business logic from UI (and avoid anonymous functions/callbacks) var numbers = [2, 4, 1, 3, 5]; // bad $("a.sort-numbers").on("click", function (e) { e.preventDefault(); numbers.sort(); }); // good var sortNumbers = function (e) { e && e.preventDefault && e.preventDefault(); numbers.sort(); }; $("a.sort-numbers").on("click", sortNumbers);
  17. 17. Advanced stuff!
  18. 18. Asynchronous tests
  19. 19. var asyncSort = function (numbers, callback) { setTimeout(function () { callback(numbers.sort()); }, 10); };
  20. 20. define("asyncSort", function () { it("should sort my numbers", function (done) { asyncSort([1, 3, 2], function (result) { assert.deepEqual(result, [1, 2, 3]); done(); }); }); });
  21. 21. Sinon.js npm install -g sinon
  22. 22. Spies var sinon = require("sinon"); it("runs jQuery.ajax", function () { sinon.spy($, "ajax"); doAjaxCall(); assert($.ajax.calledOnce); $.ajax.restore(); }); it("does some thing that takes forever", function () { someGlobal.slowFunction = sinon.spy(); callSlowFunction(); assert.equal(someGlobal.slowFunction.callCount, 1); assert(someGlobal.slowFunction.calledWith(1, "two", 3)); });
  23. 23. Stubs var sinon = require("sinon"); it("returns the age of a person with data stored in the database", function () { Database.get = sinon.stub().returns({ name: "Joe", age: 33 }); var getAge = function () { return Database.get("Joe").age; }; assert.equals(getAge(), 33); });
  24. 24. Mocks var sinon = require("sinon"); it("should get the desired car from the database", function () { var mock = sinon.mock(Database); mock .expects("getCar") .withExactArgs("Honda Civic") .once() var car = new Car(); car.get("Honda Civic"); assert(mock.verify()); });
  25. 25. Fake timers var sinon = require("sinon"); it("should save after 30 seconds", function () { var clock = sinon.useFakeTimers(); sinon.spy($, "ajax"); delayedSave(); clock.tick(30001); assert($.fn.ajax.called); $.ajax.restore(); });
  26. 26. jsdom and node-jquery Test browser-dependent code Make Node think it's a browser Test jQuery DOM manipulations Go through all stages of grief getting it to work Ponder using a browser-based framework instead
  27. 27. Install npm install -g jsdom && npm install -g jquery
  28. 28. Set up GLOBAL.document = require("jsdom").jsdom(); GLOBAL.window = document.createWindow(); GLOBAL.$ = GLOBAL.jQuery = require("jquery").create(window);
  29. 29. Use it("should change div background color to blue", function () { $("body").html('<div id="mydiv"></div>'); $("#mydiv").css("background", "blue"); assert.equal($("#mydiv").css("background"), "blue"); });
  30. 30. No headless browser No GUI running in background No guarantees
  31. 31. THE END Questions? Twitter: Email: @JoshMock josh@joshmock.com github.com/JoshMock/mocha-node-slides

×