This presentation deals with a complex approach to application testing in back end and front end parts, tests writing and common mistakes. It also includes a short overview of libraries and frameworks for creation of tests, as well as practical examples of code.
Presentation by Pavlo Iuriichuk, Lead Software Engineer, GlobalLogic, Kyiv), delivered at an open techtalk on December 11, 2014.
More details - http://globallogic.com.ua/report-web-testing-techtalk-2014
2. Plan
1. 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
4. 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
5. 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
6. Test runner
Test’em - simple test
runner
1. Framework config:
Mocha, Jasmine
2. Test files
3. Serve files
4. Browser stack config
7. Test runner
Karma - advanced test
runner
1. Plugins
2. Multiple report formats
supported
3. Various browsers
4. Dynamic index.html
generation
8. Test runner
Essentials
1. Synchronization between source files
2. Integration of frameworks
3. Debugging
9. Unit testing stack
Testing framework
API
● TDD
● BDD
Main frameworks
● Mocha
● Jasmine
● describe
o skip
o only
● it
● before(done)
● after(done)
● beforeEach
● afterEach
10. 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’)
11. 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
13. 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
● element
o sendKeys
o setPosition
o setSize
15. 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
20. Mocking of data providers
Faker.js
● id’s
● names, emails
● cities, locations
● messages, sentences, paragraphs
Sinon.js
● Mocking API using sinon.mock(API)
21. 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;
}
22. 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
23. Sample code
var 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');
25. 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.
26. 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)
}
27. Sample code
var 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;
}
}
28. 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
29. 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
30.
31.
32. References
Tools:
● WS:
o WebSocket API client
● HTTP:
o Nock
Article:
● https://davidbeath.com/posts/testing-http-responses-in-nodejs.
html
33. 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
34. 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
35. Worst
1. To mix TDD and BDD
a. TDD: Suite, test, step, setup, done
b. BDD: Expectations, asserts
2. To spaghetti the dependencies inside test
code
36. Sample code
describe('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;
37. 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