Top Banner
with Testing 1
37

Testing with Node.js

Jan 27, 2015

Download

Technology

Jonathan Waller

An introduction on testing Node.js code.

Covers frontend (UI) testing, backend unit tests and code coverage.
Also mentions how to use a Makefile to run frontend and backend tests at the same time.
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Testing with Node.js

withTesting

1

Page 2: Testing with Node.js

Self introduction

Jonathan Waller

2

Page 3: Testing with Node.js

Content

What is Node.js?

Testing the code

Checking test coverage

Testing the user interface

Pulling it all together

3

Page 4: Testing with Node.js

4

WHAT IS NODE.JS?

Page 5: Testing with Node.js

What is Node.js?

$  node  example.jsServer  running  at  http://127.0.0.1:8080/

var  http  =  require('http');

http.createServer(function  (request,  response)  {   response.writeHead(200,  {'Content-­‐Type':  'text/plain'});   response.end('Hello  World\n');}).listen(8080);

console.log('Server  running  at  http://127.0.0.1:8080/');

Running it

example.js

5

Page 6: Testing with Node.js

Node is non-blockingBlocking code

var  fileContents1  =  fs.readFileSync('file1.txt');console.log(fileContents1);

var  fileContents2  =  fs.readFileSync('file2.txt');console.log(fileContents2);

6

0s 5s 10s

Page 7: Testing with Node.js

Node is non-blockingNon-blocking code

var  callback  =  function(err,  fileContents){   console.log(fileContents);}

fs.readFile('file1.txt',  callback);fs.readFile('file2.txt',  callback);

7

0s 5s 10s

Page 8: Testing with Node.js

$  node  example.js

8

Page 9: Testing with Node.js

9

TESTING THE CODE

Page 10: Testing with Node.js

Testing the code

10

EXPECT.JS

MOCHA

expect(myObject.id).to.be(undefined);expect(myObject).to.eql({  a:  'b'  })expect(myVariable1).to.be.a('number');expect(myVariable2).to.be.an('array');

describe('file.js',  function()  {   describe('functionName',  function()  {     it('action',  function()  {       ...

Page 11: Testing with Node.js

11

Page 12: Testing with Node.js

function  readFile1(){   return  fs.readFileSync('file1.txt');}

function  readFile2(){   return  fs.readFileSync('file2.txt');}

modules.exports.readFile1  =  readFile1;modules.exports.readFile2  =  readFile2;

12

SYNC_EXAMPLE.JS

TESTING SYNCHRONOUS CODE 1

var  fileContents1  =  fs.readFileSync('file1.txt');console.log(fileContents1);

var  fileContents2  =  fs.readFileSync('file2.txt');console.log(fileContents2);

var  sync_example  =  require(‘./sync_example’);

TEST/SYNC_EXAMPLE.JS

SYNC_EXAMPLE.JS

Page 13: Testing with Node.js

function  readFile1(){   return  fs.readFileSync('file1.txt');}

function  readFile2(){   return  fs.readFileSync('file2.txt');}

modules.exports.readFile1  =  readFile1;modules.exports.readFile2  =  readFile2;

13

var  sync_example  =  require(‘../sync_example’);

describe('sync_example.js',  function()  {   describe('readFile1',  function()  {     it('reads  the  content  of  the  file',  function()  {       var  fileContents1  =  sync_example.readFile1();       expect(fileContents1.length).to.be.greaterThan(0);     });   });   describe('readFile2',  function()  {     it('reads  the  content  of  the  file',  function()  {       var  fileContents2  =  sync_example.readFile2();       expect(fileContents2.length).to.be.greaterThan(0);     });   });});

TEST/SYNC_EXAMPLE.JS

SYNC_EXAMPLE.JS

TESTING SYNCHRONOUS CODE 2

Page 14: Testing with Node.js

function  readFile1(callback){   fs.readFile('file1.txt',  callback);}

function  readFile2(callback){   fs.readFile('file2.txt',  callback);}

modules.exports.readFile1  =  readFile1;modules.exports.readFile2  =  readFile2;

14

ASYNC_EXAMPLE.JS

TESTING ASYNCHRONOUS CODE 1

var  callback  =  function(err,  fileContents){   console.log(fileContents);}

fs.readFile('file1.txt',  callback);fs.readFile('file2.txt',  callback);

ASYNC_EXAMPLE.JS

Page 15: Testing with Node.js

function  readFile1(callback){   fs.readFile('file1.txt',  callback);}

function  readFile2(callback){   fs.readFile('file2.txt',  callback);}

modules.exports.readFile1  =  readFile1;modules.exports.readFile2  =  readFile2;

15

describe('async_example.js',  function()  {   describe('readFile1',  function()  {     it('reads  the  content  of  the  file',  function(done)  {       async_example.readFile1(function(err,fileContents1){         expect(fileContents1.length).to.be.greaterThan(0);         done();       });     });   });   describe('readFile2',  function()  {     it('reads  the  content  of  the  file',  function(done)  {       async_example.readFile2(function(err,fileContents2){         expect(fileContents2.length).to.be.greaterThan(0);         done();       });     });   });});

TEST/ASYNC_EXAMPLE.JS

ASYNC_EXAMPLE.JS

TESTING ASYNCHRONOUS CODE 2

Page 16: Testing with Node.js

16

async_example.readFile1(function(err,fileContents1){   expect(fileContents1.length).to.be.greaterThan(0);   done();});

TESTING ASYNCHRONOUS CODE 3

var  callback1  =  function(err,fileContents1){   expect(fileContents1.length).to.be.greaterThan(0);   done();}async_example.readFile1(callback1);

=

Page 17: Testing with Node.js

$  mocha  test/example.js  -­‐r  expect.js

17

Page 18: Testing with Node.js

JSCoverage

18

CHECKING TEST COVERAGE

Page 19: Testing with Node.js

19

Page 20: Testing with Node.js

Checking test coverage

20

JSCoveragejson-cov$  jscoverage  index.js

Page 21: Testing with Node.js

Checking test coverage

21

Running tests (Running the instrumented code)$  mocha  test/index.js  -­‐R  json-­‐cov  >  coverage.html

$  jscoverage  index.js

Instrumenting JS file

Page 22: Testing with Node.js

SpookyJS

22

TESTING THE USER INTERFACE

Page 23: Testing with Node.js

UI testingSpookyJS is a scriptable web testing framework for Mocha

Wrapper for CasperJs and PhantomJS

Uses WebKit, so supports client-side Javascript

23

WEBKIT

CasperJS

SpookyJS

Page 24: Testing with Node.js

var  Spooky  =  require('spooky');

var  spooky  =  new  Spooky(   {     child:  {       port:  8080,       script:  './lib/bootstrap.js',  //Loads  casperJS       spooky_lib:  './node_modules'     }   },  function  (err,  error,  response)  {         if  (err  ||  error)  {       var  e  =  new  Error('Failed  to  initialize  SpookyJS');       e.details  =  err  ||  error;       throw  e;     }  

    spooky.on('error',  function  (e)  {console.error(e);});     spooky.on('console',  function  (line)  {console.log(line);});

    spooky.start();

    spooky.then(function  (){       this.echo('Hello,  this  is  SpookyJS');     });

    spooky.open('http://www.google.com/');

    spooky.then(function  ()  {       this.echo('Now  viewing:  '  +  this.getCurrentUrl());     });

    spooky.run();   });

24

SAMPLE SPOOKY SCRIPT

Page 25: Testing with Node.js

var  util  =  require('util');var  expect  =  require('expect.js');

describe("Test  that  SpookyJS  is  working",  function  ()  {   var  context  =  {};   var  hooks  =  require('../util/hooks');

  before(hooks.before(context));

  describe('Test  that  SpookyJS  can  navigate  to  Google',  function  ()  {     it('navigates  to  google.com,  and  returns  the  current  url',  function  (done)  {

      context.spooky.start();

      context.spooky.then(function  (){         this.echo('Hello,  this  is  SpookyJS');       });

      context.spooky.open('http://www.google.com/');

      context.spooky.then(function  ()  {         this.echo(this.getCurrentUrl());       });

      function  onConsole(line)  {         if  (line  ===  'http://www.google.com/')  {           context.spooky.removeListener('console',  onConsole);           done();           return;         }       }       context.spooky.on('console',  onConsole);

      context.spooky.run();

    });        });        after(hooks.after(context));});

25

TEST/FRONTEND.JS

Page 26: Testing with Node.js

$  mocha  test/frontend/example.js  -­‐r  expect.js

26

Page 27: Testing with Node.js

$  make  test

27

PULLING IT ALL TOGETHER

Page 28: Testing with Node.js

Make: Folder structure

28

testbackend:   @mocha  $$(find  test/backend  -­‐name  "*.js")  -­‐r  expect.js  -­‐R  spec

...など

Page 29: Testing with Node.js

Testing the backendMakefile

Run tests$  make  testbackend

29

testbackend:   @./node_modules/.bin/mocha  $$(find  test/backend  -­‐name  "*.js")  -­‐r  expect.js  -­‐R  spec

Page 30: Testing with Node.js

Checking test coverageMakefile

Check test coverage$  make  coverage

30

coverage:   @echo  'Checking  test  code  coverage...'

  #Cleaning  up   @rm  -­‐rf  _src-­‐with-­‐coverage/  &&  rm  -­‐rf  _test-­‐with-­‐coverage/     #Instrumenting  code   @./node_modules/jscoverage/jscoverage  src  _src-­‐with-­‐coverage

  #Creating  tests  for  instrumented  code   @cp  -­‐r  test  _test-­‐with-­‐coverage   @find  _test-­‐with-­‐coverage  -­‐name  '*.js'  -­‐exec  sed  -­‐i  ''  's/\/src\//\/_src-­‐with-­‐coverage\//g'  "{}"  \;

  #Running  tests...   @./node_modules/.bin/mocha  $$(find  _test-­‐with-­‐coverage  -­‐name  "*.js")  -­‐r  expect.js  -­‐R  html-­‐cov  >  coverage.html

  #Cleaning  up   @rm  -­‐rf  _src-­‐with-­‐coverage/  &&  rm  -­‐rf  _test-­‐with-­‐coverage/

  @echo  'Done.  Result  written  to  coverage.html.'

Page 31: Testing with Node.js

31

Page 32: Testing with Node.js

32

Run tests$  make  testfrontend

Makefile

Testing the frontend

test:   @./node_modules/.bin/mocha  $$(find  test/frontend  -­‐name  "*.js")  -­‐r  expect.js  -­‐R  spec

Page 33: Testing with Node.js

testbackend:   @./node_modules/.bin/mocha  $$(find  test/backend  -­‐name  "*.js")  -­‐r  expect.js  -­‐R  spec  testfrontend:   @./node_modules/.bin/mocha  $$(find  test/frontend  -­‐name  "*.js")  -­‐r  expect.js  -­‐R  spec  

coverage:   @echo  'Checking  test  code  coverage...'   ...   @echo  'Done.  Result  written  to  coverage.html.'

test:   @./node_modules/.bin/mocha  $$(find  test/  -­‐name  "*.js")  -­‐r  expect.js  -­‐R  spec  

all:  test  coverage   @echo  'Tested  frontend  and  backend.  Coverage  doc  saved  to  coverage.html.'

Makefile

33

Run all tests$  make  test

Run all tests + show test coverage$  make  all

Page 34: Testing with Node.js

Summary

Node.js is Javascript on the server.

Unit testing with Mocha + Expect.js

Checking coverage with JSCoverage

User interface testing with SpookyJS

Running everything with Make

34

Page 35: Testing with Node.js

Thank youありがとうございました

35

Page 36: Testing with Node.js

Contact Jonathan

@jonwaller

facebook.com/jonwaller0

gplus.to/jonwallerwww.jonwaller.net/ja/

36

Page 37: Testing with Node.js

ReferencesNode.js

http://nodejs.org/

Unit testing (Mocha)

http://visionmedia.github.com/mocha/

Test coverage

http://tjholowaychuk.com/post/18175682663/mocha-test-coverage

User interface testing

http://casperjs.org/

https://github.com/WaterfallEngineering/SpookyJS

Other useful stuff

https://npmjs.org/ - Learn about commonly used node packages

http://jenkins-ci.org/ - Set up continuous integration (e.g. Automatically testing when you commit)

37