• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Test driven node.js
 

Test driven node.js

on

  • 1,874 views

If you don’t test it, how do you know it works? Over the past few years, we have been compelled to write unit and integration tests for our applications--code that validates code--and it is these ...

If you don’t test it, how do you know it works? Over the past few years, we have been compelled to write unit and integration tests for our applications--code that validates code--and it is these tests that change a one-off tool into a well-architected, robust, business-ready application. Yet, every new framework requires a new testing framework, so in this session, we will discuss testing frameworks for node.js. You will walk away with a solid understanding of how to write tests against your node.js applications and modules, leading to confidence that your work is business-ready.

Statistics

Views

Total Views
1,874
Views on SlideShare
1,852
Embed Views
22

Actions

Likes
16
Downloads
0
Comments
0

6 Embeds 22

https://twitter.com 15
https://www.facebook.com 3
https://m.facebook.com&_=1386527544490 HTTP 1
https://m.facebook.com&_=1386566996474 HTTP 1
http://www.linkedin.com 1
https://www.linkedin.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Test driven node.js Test driven node.js Presentation Transcript

    • TEST DRIVEN
    • What is node.js? “ Node.js is a platform built on Chrome's JavaScript runtime for easily building fast, scalable network applications. ”
    • basicFundamentals
    • packageManagement
    • is not an acronym
    • is an acronym National Association of Pastoral Musicians
    • github: isaacs/npm install: comes with node
    • localInstallation npm install <package>
    • globalInstallation npm install <package> --global -g or --global
    • dualInstallation npm install <package> --link
    • dependencyReferences npm install <package> --save[-dev|-optional] --save or --save-dev or --save-optional
    • updateDependencies npm install
    • testingNode.js
    • “ TDD is to coding style as yoga is to posture. Even when you're not actively practicing, having done so colors your whole life healthier. ” j. kerr
    • assertingCorrectness
    • var  assert  =  require('assert');
    • assert(value)            .ok(value)            .equal(actual,  expected)            .notEqual(actual,  expected)            .deepEqual(actual,  expected)            .notDeepEqual(actual,  expected)            .strictEqual(actual,  expected)            .notStrictEqual(actual,  expected)            .throws(block,  [error])            .doesNotThrow(block,  [error])            .ifError(value)
    • 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var assert = require('assert'); // Will pass assert.ok(true); // Will throw an exception assert.ok(false);
    • 1 var assert = require('assert'); 2 3 // Will throw 'false == true' error 4 assert.ok(typeof 'hello' === 'number'); 5 6 7 8 9 10 11 12 13 14 15 16 17 18
    • $  node  test.js assert.js:104    throw  new  assert.AssertionError({                ^ AssertionError:  false  ==  true        at  Object.<anonymous>  (my-­‐test.js:7:8)        at  Module._compile  (module.js:449:26)        at  Object.Module._extensions..js  (module.js:467:10)        at  Module.load  (module.js:356:32)        at  Function.Module._load  (module.js:312:12)        at  Module.runMain  (module.js:487:10)        at  process.startup.processNextTick.process._tick... $  _
    • Chai Assertion Library
    • github: chaijs/chai install: npm install chai
    • isTrue,                      isFalse, isNull,                      isNotNull, isUndefined,            isDefined, isFunction,              isNotFunction, isArray,                    isNotArray, isBoolean,                isNotBoolean, isNumber,                  isNotNumber, isString,                  isNotString,                                    include,                                    lengthOf,                                    operator,                                    closeTo   isObject,                  isNotObject, typeOf,                      notTypeOf, instanceOf,              notInstanceOf, match,                        notMatch, property,                  notProperty, deepProperty,          notDeepProperty, propertyVal,            propertyNotVal, deepPropertyVal,    deepPropertyNotVal, additional assertions
    • var  assert  =  require('chai').assert;
    • 1 var assert = require('chai').assert; 2 3 // Will throw 'expected 'hello' to be a number' 4 assert.isNumber('hello'); 5 6 7 8 9 10 11 12 13 14 15 16 17 18
    • $  node  test.js expected  'hello'  to  be  a  number $  _
    • 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var chai = require('chai') , assert = chai.assert; chai.Assertion.includeStack = true; // Will throw and display stack assert.isNumber('hello');
    • testDriven
    • Exceptions alone are insufficient
    • $  node  my-­‐test.js assert.js:104    throw  new  assert.AssertionError({                ^ AssertionError:  false  ==  true        at  Object.<anonymous>  (my-­‐test.js:7:8)        at  Module._compile  (module.js:449:26)        at  Object.Module._extensions..js  (module.js:467:10)        at  Module.load  (module.js:356:32)        at  Function.Module._load  (module.js:312:12)        at  Module.runMain  (module.js:487:10)        at  process.startup.processNextTick.process._tick... $  _
    • We need a testing framework!
    • mocha simple, flexible, fun
    • mocha github: visionmedia/mocha install: npm install -g mocha
    • $  npm  install  -­‐g  mocha $  mkdir  test $  mocha        ✔  0  tests  complete  (1ms) $  
    • var  mocha  =  require('mocha');
    • tddSyntax suite('Testing  out  this  thing',  function()  {        test('should  do  stuff',  function()  {                //  Assertion  tests        }); });
    • ./test/my-test.js 1 var assert = require('chai').assert; 2 3 suite('Assertions', function() { test('should pass on truthiness', function() { 4 assert.ok(true); 5 }); 6 test('should fail on falsiness', function() { 7 assert.ok(false); 8 }); 9 10 }); 11 12 13 14 15 16
    • $  mocha  -­‐-­‐ui  tdd  -­‐-­‐reporter  spec    Assertions        ✓  should  pass  on  truthiness          1)  should  fail  on  falsiness    ✖  1  of  2  tests  failed:    1)  Assertions  should  fail  on  falsiness:              AssertionError:  false  ==  true            at  (stack  trace  omitted  for  brevity) $  _
    • groupedTests
    • groupSyntax suite('Testing  out  this  thing',  function()  {        suite('with  a  subset  of  this  other  thing',  function()  {                test('should  do  stuff',  function()  {                        //  Assertion  tests                });        }); });
    • 1 var assert = require('chai').assert; 2 3 suite('Assertions', function() { suite('of truthiness', function() { 4 test('should pass on true', function() { 5 assert.isTrue(true); 6 }); 7 test('should pass on false', function() { 8 assert.isFalse(false); 9 }); 10 }); 11 suite('of type', function() { 12 test('should pass on number', function() { 13 assert.isNumber(5); 14 }); 15 }); 16 17 }); 18
    • $  mocha  -­‐-­‐ui  tdd  -­‐-­‐reporter  spec    Assertions        of  truthiness            ✓  should  pass  on  true              ✓  should  pass  on  false          of  type            ✓  should  pass  on  number      ✔  3  tests  complete  (6ms) $  _
    • pendingTests
    • pendingSyntax suite('Testing  out  this  thing',  function()  {        suite('with  a  subset  of  this  other  thing',  function()  {                test('should  do  stuff  someday');        }); });
    • 1 var assert = require('chai').assert; 2 3 suite('Assertions', function() { suite('of truthiness', function() { 4 test('should pass on true', function() { 5 assert.isTrue(true); 6 }); 7 test('should pass on false', function() { 8 assert.isFalse(false); 9 }); 10 }); 11 suite('of type', function() { 12 test('should pass on number', function() { 13 assert.isNumber(5); 14 }); 15 test('should pass on object'); 16 }); 17 18 });
    • $  mocha  -­‐-­‐ui  tdd  -­‐-­‐reporter  spec    Assertions        of  truthiness            ✓  should  pass  on  true              ✓  should  pass  on  false          of  type            ✓  should  pass  on  number              -­‐  should  pass  on  object    ✔  4  tests  complete  (6ms)    •  1  test  pending $  _
    • setupTeardown
    • setup(); teardown();
    • setupTeardown suite('Testing  out  this  thing',  function()  {        setup(function(){                //  ...        };        suite('with  a  subset  of  this  other  thing',  function()  {                test('should  do  stuff',  function()  {                        //  Assertion  tests                });                teardown(function(){                        //  ...                };        }); });
    • asynchronousTests
    • asynchronousSyntax test('it  should  not  error',  function(done)  {        search.find("Apples",  done); });
    • asynchronousSyntax test('it  should  not  error',  function(done)  {        search.find("Apples",  done); }); test('it  should  return  2  items',  function(done)  {        search.find("Apples",  function(err,  res)  {                if  (err)  return  done(err);                res.should.have.length(2);                done();        }); });
    • All Mocha functions accept this callback
    • 1 suite('When searching for Apples', function(done) { setup(function(done){ 2 items.save(['fiji apples', 3 'empire apples'], done); 4 }); 5 test('it should not error', function(done) { 6 search.find("Apples", done); 7 }); 8 test('it should return 2 items', function(done) { 9 search.find("Apples", function(err, res) { 10 if (err) return done(err); 11 res.should.have.length(2); 12 done(); 13 }); 14 }); 15 16 }); 17 18
    • simplifyExecution
    • be nice to yourself: $  mocha  -­‐-­‐ui  tdd  -­‐-­‐reporter  spec should be simplified to $  make  test and $  npm  test
    • ./makefile 1 # Makefile for sample module 2 3 test: mocha --reporter spec --ui tdd 4 5 6 7 8 .PHONY: test 9 10 11 12 13 14 15 16
    • ./makefile 1 # Makefile for sample module 2 3 test: mocha 4 --reporter spec 5 --ui tdd 6 7 8 .PHONY: test 9 10 11 12 13 14 15 16
    • ./package.json 1 { "name": "sample", 2 "version": "0.1.0", 3 "devDependencies": { 4 "chai": "~1.2.0" 5 }, 6 "scripts": { 7 "test": "make test" 8 } 9 10 } 11 12 13 14 15 16
    • $  make  test    Assertions        ✓  should  pass  on  truthiness          1)  should  fail  on  falsiness    ✖  1  of  2  tests  failed:    1)  Assertions  should  fail  on  falsiness:              AssertionError:  false  ==  true            at  (stack  trace  omitted  for  brevity) $  _
    • $  npm  test    Assertions        ✓  should  pass  on  truthiness          1)  should  fail  on  falsiness    ✖  1  of  2  tests  failed:    1)  Assertions  should  fail  on  falsiness:              AssertionError:  false  ==  true            at  (stack  trace  omitted  for  brevity) $  _
    • eliminate global dependency $  npm  install  mocha  -­‐-­‐link
    • 1 test: @./node_modules/.bin/mocha 2 --reporter spec 3 --ui tdd 4 5 6 .PHONY: test 7 8 9 10 11 12 13 14 15 16 17 18
    • update dev dependencies $  npm  install  mocha  -­‐-­‐save-­‐dev $  npm  install  chai    -­‐-­‐save-­‐dev
    • $  npm  install  mocha  -­‐-­‐save-­‐dev $  npm  install  chai    -­‐-­‐save-­‐dev $  git  diff  package.json   diff  -­‐-­‐git  a/package.json  b/package.json index  439cf44..3609bb9  100644 -­‐-­‐-­‐  a/package.json +++  b/package.json @@  -­‐1,5  +1,7  @@  {      "name":  "sample", -­‐    "version":  "0.1.0" +    "version":  "0.1.0", +    "devDependencies":  { +        "mocha":  "~1.4.0", +        "chai":  "~1.2.0" +    }  }
    • notificationSystems
    • slowThreshold mocha --slow <ms> -s <ms> or --slow <ms>
    • $  mocha  -­‐-­‐reporter  spec  -­‐-­‐slow  5    When  accessing  the  Ticket  API        with  valid  Morale  credentials,            and  with  a  project  that  exists,                getting  a  list  of  tickets                    ✓  should  return  without  an  error                      ✓  should  return  a  populated  array  (5ms)                    ✓  should  contain  a  task  or  bug  ticket                  adding  a  new  ticket                    ✓  should  return  without  an  error                      ✓  should  return  the  new  ticket  (11ms)  ✔  5  tests  complete  (22ms) $  _
    • continuousTesting mocha --watch -w or --watch
    • $  mocha  -­‐-­‐watch  ✔  5  tests  complete  (22ms)  ^  watching
    • Growl
    • mac: apple app store win: growlForWindows.com also: growlNotify
    • growlNotifications mocha --growl -G or --growl
    • ⌘S
    • 1 test: @./node_modules/.bin/mocha 2 --reporter spec 3 --ui tdd 4 5 6 watch: @./node_modules/.bin/mocha 7 --reporter min 8 --ui tdd 9 --growl 10 --watch 11 12 13 .PHONY: test watch 14 15 16 17 18
    • behaviorDriven
    • tddSyntax suite('Test  this  thing',  function()  {        test('Do  stuff',  function()  {                //  Assertion  tests        }); }); bddSyntax describe('Testing  out  this  thing',  function()  {        it('should  do  stuff',  function()  {                //  Assertion  tests        }); });
    • 1 test: @./node_modules/.bin/mocha 2 --reporter spec 3 --ui bdd 4 5 6 watch: @./node_modules/.bin/mocha 7 --reporter min 8 --ui bdd 9 --growl 10 --watch 11 12 13 .PHONY: test 14 15 16 17 18
    • 1 test: @./node_modules/.bin/mocha 2 --reporter spec 3 4 5 6 watch: @./node_modules/.bin/mocha 7 --reporter min 8 --growl 9 --watch 10 11 12 13 .PHONY: test 14 15 16 17 18
    • setupTeardown
    • before(); beforeEach(); after(); afterEach();
    • setupTeardown describe('Testing  out  this  thing',  function()  {        before(function(){                //  ...        };        describe('with  a  subset  of  that  thing',  function()  {                it('should  do  stuff',  function()  {                        //  Assertion  tests                });                afterEach(function(){                        //  ...                };        }); });
    • There is no tdd equivalent to ‘each’
    • tddMethods suite(); test(); setup(); teardown(); bddMethods describe(); it(); before(); after(); beforeEach(); afterEach();
    • expectAssertions
    • assertSyntax assert.isObject(person); assert.property(person,  "age"); assert.isNumber(person.age); assert.equals(person.age,  34); expectSyntax expect(person).to.be.an('object');        .with.property('age')        .that.is.a('number')        .that.equals(34);
    • var  expect  =  require('chai').expect;
    • assertionChains for readability
    • expect(person).to.exist        .and.be.an('object')        .with.property('age')        .that.is.to.exist        .and.is.a('number')        .and.equals(34);
    • .to .be .been .is .that .and .have .with syntaxSugar for readability
    • expect(person).to.exist        .and.be.an('object')        .with.property('age')        .that.is.to.exist        .and.is.a('number')        .and.equals(34);
    • expect(person).to.exist        .and.be.an('object')        .with.property('age')        .that.is.to.exist        .and.is.a('number')        .and.equals(34);
    • .property subjectChange from original object
    • expect(person)    .that.is.an('object')    .with.property('address')        .that.is.an('object')        .with.property('city')            .that.is.a('string')            .and.equals('Detroit')
    • shouldAssertions
    • assertSyntax assert.isObject(person); assert.property(person,  "age"); assert.isNumber(person.age); assert.equals(person.age,  34); shouldSyntax person.should.be.an('object')        .with.property('age')        .that.is.a('number')        .that.equals(34);
    • var  should  =  require('chai').should();
    • var  chai      =  require('chai')    ,  expect  =  chai.expect    ,  should  =  chai.should();
    • assertionChains same as expect style* except for existence
    • expect(foo).to.not.exist; expect(bar).to.exist; should.not.exist(foo); should.exist(foo);
    • skippedTests
    • skipSyntax describe('Testing  out  this  thing',  function()  {        it.skip('should  be  skipped',  function()  {                //  Assertion  tests        }); }); describe.skip('This  entire  suite  will  be  skipped',  function()  {        it('should  do  stuff',  function()  {                //  Assertion  tests        }); });
    • 1 describe('Assertions', function() { describe('of truthiness', function() { 2 it('should pass on truthiness', function() { 3 assert.isTrue(true); 4 }); 5 it('should pass on falsiness', function() { 6 assert.isFalse(false); 7 }); 8 }); 9 describe('of type', function() { 10 it.skip('should pass on number', function() { 11 assert.isNumber(5); 12 }); 13 it('should pass on object'); 14 }); 15 16 }); 17 18
    • $  make  test    Assertions        of  truthiness            ✓  should  pass  on  truthiness              ✓  should  pass  on  falsiness          of  type            -­‐  should  pass  on  number              -­‐  should  pass  on  object    ✔  4  tests  complete  (6ms)    •  2  test  pending $  _
    • Skip is available in bdd only
    • mockingObjects
    • JavaScript ships with a mocking framework ...it’s called JavaScript
    • 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var me = {firstName: 'Jay' , lastName: 'Harris' , getFullName: function() { return this.firstName + ' ' + this.lastName; }}; // Returns 'Jay Harris' me.getFullName(); me.getFullName = function() { return 'John Doe'; }; // Returns 'John Doe' me.getFullName();
    • nock HTTP Mocking Library
    • nock github: flatiron/nock install: npm install nock
    • 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var http = require('http'); var reqOptions = { host: 'api.twitter.com', path: '/1/statuses/user_timeline.json?' + 'screen_name=jayharris' }; var resCallback = function(res) { var responseData = ''; res.on('data', function(chunk) { responseData += chunk; }); res.on('end', function() { console.log(responseData); }); }; http.request(reqOptions, resCallback).end();
    • 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var nock = require('nock'); var twitter = nock('http://api.twitter.com') .get('/1/statuses/user_timeline.json?'+ 'screen_name=jayharris') .reply(200, "This worked"); // Returns "This worked" http.request(reqOptions, resCallback).end();
    • 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 // Returns live Twitter data http.request(reqOptions, resCallback).end(); var nock = require('nock'); var twitter = nock('http://api.twitter.com') .get('/1/statuses/user_timeline.json?'+ 'screen_name=jayharris') .reply(200, "This worked"); // Returns "This worked" http.request(reqOptions, resCallback).end(); // Returns live Twitter data http.request(reqOptions, resCallback).end();
    • nock nock.recorder.rec(  ); nock.recorder.play(  );
    • Sinon.js Spies, Stubs, & Mocks
    • Sinon.js github: cjohansen/Sinon.JS install: npm install sinon
    • browserTesting
    • Zombie.js Fast, headless browser
    • Zombie.js github: assaf/zombie install: npm install zombie
    • loadTesting
    • nodeload Performance Suite
    • nodeload github: benschmaus/nodeload install: npm install nodeload
    • activelyPractice
    • Color your whole life healthier
    • jay harris P R E S I D E N T jay@aranasoft.com #testdrivennode @jayharris