Node.js Unit Tests
ironSource Node.js course
rotem.tamir@ironsrc.com | @_rtam on twitter
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
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
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
Tools of the trade
● Test Runner -> mocha.js
● Assertion Framework -> chai.js
● Stubbing/Mocking tools -> sinon.js
Anatomy of a unit test
setup assert cleanup
Mocha.js
setup assert cleanup
before()
beforeEach()
it() after()
afterEach()
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/
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
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', () => {})
})
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
Why are these tests bad?
● They test someone else’s code
● They make I/O!
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/
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
Bonus: pick your poison
● Testing Webservers
● Coverage reports with istanbul
● Syntactic sugar with sinon-as-promised, sinon-chai
● Integrating unit tests into CI/CD
Thank you
@_rtam

Unit tests in node.js

  • 1.
    Node.js Unit Tests ironSourceNode.js course rotem.tamir@ironsrc.com | @_rtam on twitter
  • 2.
    Why test? ● TestsReduce 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 ● Isolateeach 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 shouldcome 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 thetrade ● Test Runner -> mocha.js ● Assertion Framework -> chai.js ● Stubbing/Mocking tools -> sinon.js
  • 6.
    Anatomy of aunit test setup assert cleanup
  • 7.
  • 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 sometests ● 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 differentcalls 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 thesetests 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 ourgetMyIP’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 yourpoison ● Testing Webservers ● Coverage reports with istanbul ● Syntactic sugar with sinon-as-promised, sinon-chai ● Integrating unit tests into CI/CD
  • 16.