full stack unit testing

Post on 12-Jul-2015

1.061 Views

Category:

Engineering

7 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Full-stack unit-

testingTech talk @ Pause

Plan1. Overview of frameworks and libraries for testing

2. Testing of client side web application

a. Test runner

b. Unit testing stack

c. End-2-end testing

d. Reporting

e. Sample: angular application testing

3. Testing of server side

a. Mocking of data providers

b. Fixtures

c. Essentials of tests

4. Pitfalls of unit testing

Overview of frameworks

Testing of client-side

1. Test runner - runs unit tests suite in various

browsers and write reports using different

formats

2. Frameworks - skeleton for unit tests suites

3. Utils libraries - allow to write tests in more

expressive

Test runner

1. Dynamically generate index file using

required libs, sources and tests

2. Execute web server on background

3. Run tests in different browsers

4. Collect test results from expectations and

asserts

5. Format them into report

Test runner

Test’em - simple test

runner1. Framework config:

Mocha, Jasmine

2. Test files

3. Serve files

4. Browser stack config

Test runner

Karma - advanced test

runner1. Plugins

2. Multiple report formats

supported

3. Various browsers

4. Dynamic index.html

generation

Test runner

Essentials

1. Synchronization between source files

2. Integration of frameworks

3. Debugging

Unit testing stack

Testing framework

API● TDD

● BDD

Main frameworks● Mocha

● Jasmine

● describeo skip

o only

● it

● before(done)

● after(done)

● beforeEach

● afterEach

Unit testing stack

Assertion libraries

Chai● Plugins

● Supports should and

expect style

Should

● expect(foo).to.deep.

equal(someNested

Array)

● should.exist(foo)

● foo.bar.should.have

.property(‘bar’)

Unit testing stack

Plugins for chai

● Allows you to write

tests in terms of

libraries you are

using

● Syntactic sugar

● Sinon.js

● jQuery

● Backbone

● Q

Unit testing stack

End-2-end testing

Protractor (previously

angular-scenario):

● Access to angular

scope from view

● Selectors for

directives

● Uses selenium

● by.o id

o css

o model

o binding

● elemento sendKeys

o setPosition

o setSize

End-2-end testing

Reporting

● jUnit XML - Jenkins

love it

● Progress, Dots - for

console lovers

● Coverage -

objective metrics

● jUnit is has better

support of Jasmine

● Coverage settings -

include all sources

not tests

Reporting

Sample angular app testingbeforeEach(inject(function ($controller, $rootScope) {

scope = $rootScope.$new();

GamesCtrl = $controller('HotelsCtrl', {

$scope: scope, Hotels: factory

});

}));

it('should set default value for orderProp', function () {

expect(scope.orderProp).toBe('title');

});

it('should have a List of Hotels', function () {

expect(scope.games.length).toBe(2);

expect(scope.games[0].title).toBe('Hilton');

expect(scope.games[1].freeRooms).toBe(10);

});

Testing of server side

Mocking of data providers

Faker.js

● id’s

● names, emails

● cities, locations

● messages, sentences, paragraphs

Sinon.js

● Mocking API using sinon.mock(API)

Sample code//Hotels data

'use strict';

var Faker = require('Faker');

function generateOne() {

return {

name: Faker.random.bk_noun(),

address: Faker.Addresses.streetAddress(),

capacity: {

standard: Faker.helpers.randomNumber(100),

economy: Faker.helpers.randomNumber(100),

luxury: Faker.helpers.randomNumber(100)

}

};

}

module.exports.generateOne = generateOne;

module.exports.generateMany = function (count) {

var result = [];

for (var i = 0; i < count; i++) {

result.push(generateOne())

}

return result;

}

Database mapping testing

1. No need to test mongoose API

2. Create stub data using Faker API and

predefined JSON

3. Insert it into DB inside before callback

4. Run unit test suites on test data

5. Remove data from DB inside after callback

Sample codevar fixtures = require('fixtures.js');

var api = require('api/');

var expect = require('chai').expect;

var COUNT = 100;

describe('Booking API', function () {

describe('#search', function () {

before(function (done) {

fixtures.prepareData('hotels',

COUNT, done);

});

it('should return all hotes if no query

params provided', function (done)

{api.search('hotels', function (err,

data) {

expect(err).to.be.null;

expect(data).to.be.an('object');

expect(data.length).to.be.eql(COUNT);

done();

….

after(function (done) {

fixtures.destroyData('hotels');

Alternatives

● https://github.com/petejkim/factory-lady

● http://chaijs.com/plugins/chai-factories

● https://www.npmjs.com/package/rosie

Fixtures

Rules

1. Do not hardcode the id’s and data that is

generated by database

2. Put all domain specific data into fixtures,

group them by collections

3. Do not put null to client API object. Use

dummy object instead.

Sample code// Fixtures

var async = require('async');

var hotelsData = require('./hotelsData');

var Hotel = require('./hotelModel');

module.exports.prepareData = function (name, count, cb) {

if (name !== 'hotels') { cb(new Error('Invalid data type')); return; }

async.forEach(hotelsData.generateMany(count), function (item, callback) {

var hotel = Hotel.createNew(item);

hotel.save(callback);

}, cb)

}

Sample codevar client = null;

function notInitializedThrow () {throw new Error

('Client not initialized')};

module.exports.init = function (config, cb) {

if (client === null) {

client = API.createClient(config);

// doing some initializations tuff

client.on('error', cb);

client.on('connected', cb.bind(this, null));

}

}

module.exports.getClient = function () {

if (client === null) {

return {

method1: notInitializedThrow,

method2: notInitializedThrow

}

} else {

return client;

}

}

Essentials

1. Test should not depend on each others

results

2. They should not use shared data (only in

read only mode)

3. Do not allow skipped tests in releases

4. Tests are not just for make it green

Integration tests

1. They are checking of how modules are

working together

2. Ideal for checking of entity lifecycle -

creation, linking to others, api calls,

querying, destroying

3. Execution environment should be

configurable

References

Tools:

● WS:o WebSocket API client

● HTTP:o Nock

Article:● https://davidbeath.com/posts/testing-http-responses-in-

nodejs.html

Stack

1. Mocha as core framework

2. Chai / Expect as assertions

3. Request.js for HTTP requests

4. node-websocket as ws client

5. Faker or factory-lady for generation of test

data

Best

1. To put grunt test or test command as git

merge to master hook

2. To put shortcut for testing into npm test

assuming that grunt is not globally installed

3. JSHint/JSLint as pre commit hook

Worst

1. To mix TDD and BDDa. TDD: Suite, test, step, setup, done

b. BDD: Expectations, asserts

2. To spaghetti the dependencies inside test

code

Sample codedescribe('API method', function () {

var temporaryData = null;

it('should do one thing', function (done) {

var result = API.call('somemethod');

temporaryData = API.call('anotherMethod');

expect(result).to.have.keys(['code', 'details', 'message']);

});

it('should do another thing', function (done) {

API.call('setup', temporaryData);

var result = API.call('anotherMethod');

expect(result).to.be.null;

Pitfalls

1. Separated environment for integration testing, unit

testing development and production

2. Do not rely on synchronous operations especially when

they are not (callbacks, initialization process)

3. Extra console.log’s are breaking unit test reportings

Sample codedescribe('Service API', function () {

before(function (done) {

thirdparty1.init(/*callback?*/);

thirdparty2.init(/*callback?*/);

thirdparty3.init(/*callback?*/);

done();

});

before(function (done) {

thirdparty1.done(/*callback?*/);

thirdparty2.done(/*callback?*/);

thirdparty3.done(/*callback?*/);

done();

});

});

describe('Service API', function () {

before(function (done) {

async.waterfall([

thirdparty1.init,

thirdparty2.init,

thirdparty3.init

], done);

});

before(function (done) {

async.waterfall([

thirdparty1.done,

thirdparty2.done,

thirdparty3.done

], done);

});

});

References

Books1. Testable Javascript book

2. JavaScript Allongé

3. Testing with CoffeeScript

Articles/Blogs:1. Full spectrum testing with angular.js and Karma

2. Cross-browser testing on multiple devices

3. Mocha + CoffeeScript tutorial

4. http://code.tutsplus.com/tutorials/testing-in-nodejs--net-35018

QA

top related