Slides from a talk about unit tests in Node.js. The talk was held as a part of an internal Node.js course in ironSource's offices in Tel-Aviv. On Wednesday, September 14th, 2016
2. Why test?
● Tests Reduce Bugs
● Tests are good documentation
● Tests allow safe refactoring
● Tests reduce the cost of change
● Testing forces you to think
● Tests reduce fear!
Source:
http://www.slideshare.net/manatok/unit-and-integration-testing-40858470/10-A_study_conducted_by_Microsoft
3. Unit Tests
● Isolate each part of the
program
● Show that the individual
parts are correct
Integration Tests
● Test the inter-operation
of multiple subsystems
● Test that “the nuts fit
the bolts”
Source:
http://www.slideshare.net/manatok/unit-and-integration-testing-40858470/10-A_study_conducted_by_Microsoft
4. Unit tests should come FIRST!
● Fast - 1K+ per second
● Isolated - Perform no I/O
● Repeatable - Run in any order, without intervention
● Self-validating - No external tool to evaluate results
● Timely - written before code
Source: http://agileinaflash.blogspot.co.il/2009/02/first.html
5. Tools of the trade
● Test Runner -> mocha.js
● Assertion Framework -> chai.js
● Stubbing/Mocking tools -> sinon.js
8. Chai.js - assertions
● expect( <this> ).to.<assertion>(that)
● Throws an Error if the assertion is false!
Examples:
● expect(user.score).to.be.above(100)
● expect(installer).to.have.property('publisher')
● expect(obj).to.eql({a: 1}) // deep equality
http://chaijs.com/api/bdd/
9. Exercise: Write some tests
● Create a new node module (mkdir lesson-5 && npm init -y)
● Install devDeps (npm i -g mocha, npm i --save-dev chai)
● Configure an “npm test” command
● Test these cases:
○ Odd Number -> returns false
○ Even Number -> returns true
○ Invalid Input -> throws an exception
function isEven(n) {
let e = n % 2
if (Number.isNaN(e)) throw Error('Not a number!')
return !e
}
Gist
10. Testing Async Behavior
● Invoke the callback when your test is complete.
● By adding a callback (usually named done) to it(), Mocha will know that
it should wait for this function to be called to complete the test.
describe('Async behavior', function() {
before(function(done) {
somethingAsync(done)
})
it('should do ok', () => {})
})
11. Exercise: Test different calls to ipify.org
● ipify.org - has 3 formats, regular, json and jsonp
● Write a unit test which tests each type
● I use “axios” = request library with promises
const request = require('axios')
function getMyIP(fmt) {
fmt = typeof fmt == 'undefined' ? 'json' : fmt;
return request.get(`https://api.ipify.org?format=${fmt}`)
}
gist
12. Why are these tests bad?
● They test someone else’s code
● They make I/O!
13. Sinon.js - stubbing, mocking, spying
● sinon.stub(obj, ‘method’).returns(1)
What this does:
● Replaces obj.method() with function() { return 1 }
● Obj.method becomes a spy (gets special methods for
inspection)
● Gets a .reset() method which rolls counters back
● Gets a .restore() method which restores everything back
http://sinonjs.org/
14. Exercise: test our getMyIP’s different cases
● Stub axios.get
● Don’t forget to restore
● Test 3 cases:
○ No Input
○ JSON
○ JSONP
● Goals:
○ Test that Axios is called correctly
○ Don’t break the function’s signature
15. Bonus: pick your poison
● Testing Webservers
● Coverage reports with istanbul
● Syntactic sugar with sinon-as-promised, sinon-chai
● Integrating unit tests into CI/CD