2
Most read
6
Most read
8
Most read
Unit testing
Overview
• Unit testing frameworks
• Jasmine (in details)
• Test runners
• Karma (in details)
• Angular mocks
• Testing controllers
• Testing services
Unit testing frameworks
• Jasmine
– Exposes BDD no additional set up and
configuration required
• Mocha
– Requires additional configuration can
work as TDD or BDD. Normally is being
combined with Chai
• QUnit
Jasmine
• Requires less setup
• Is integrated with most CI
• Is supported by test runners or can run
from browser
• Is fully BDD
• Has built in assertion library
• Does not have built in mocking
frameworks(works fine with 3rd party like
Squire or angular-mocks)
• The syntax is really good
Mocha
• Requires more setup
• Is not fully integrated CI
• Although can be executed via test
runners or CI plugins
• Provides ability to choose between TDD
or BDD
• Works fine with 3rd party assertion and
mocking libraries
• Is integrated with IDE(Web Storm)
• Testing async is smooth
Jasmineshortest testsample
//describe function for the test suite
describe("This is test suite", function() {
//it function for the spec
it("contains spec with an expectation", function() {
//expect assertion function
expect(true)
//toBe is a matcher function
.toBe(true);
});
});
Jasminetest suite
• Is done with describe function
• describe expect as a first argument string
with test suite description as a second
function to be called to process test suite
• Can be nested
Test suite is a collection of test cases that are intended to be
used to test a software program to show that it has some
specified set of behaviors. A test suite often contains detailed
instructions or goals for each collection of test cases and
information on the system configuration to be used during
testing. Wiki (c)
Jasminetest spec
• Is done with it function
• it expect as a first argument string with
test suite description as a second
function to be called to process test
suite
• Contain expectations
Jasmineexpectations
• Expectations are built with the function
expect which takes a value, called the
actual. It is chained with a Matcher
function, which takes the expected value.
expect(true).toBe(true);
expect(true).not.toBe(false);
Matcherfunctions
• toBe()
• toEqual()
• toMatch()
• toBeDefined()
• toContain()
• toBeGreaterThan()
• toBeNull()
• And others
• You can create custom matchers as well
• Useful library jasmine-matchers
JasmineTearUpandTearDown
• beforeEach – tear up
• afterEach – tear down
describe("A spec (with setup and tear-down)", function() {
var foo = 0;
//will add 1 before each spec
beforeEach(function() {
foo += 1;
});
//will set it to 0 after each spec
afterEach(function() {
foo = 0;
});
//2 specs will verify that foo is equal to 1
it("is just a function, so it can contain any code", function() {
expect(foo).toEqual(1);
});
it("can have more than one expectation", function() {
expect(foo).toEqual(1);
});
});
Jasminespies
• At the very high level can be treated as
mocks
• Can mock the call and record passed
parameters
• Can return fake values
• Can mock the call and pass through to
real function
spyOn(foo, "getBar").and.returnValue(745);
spyOn(foo, 'getBar').and.callThrough();
spyOn(foo, 'setBar');
Jasminespies
describe("Spy sample", function() {
var foo, bar = null;
beforeEach(function() {
foo = {
setBar: function(value) { bar = value; }
};
//spy on set bar method
spyOn(foo, 'setBar');
foo.setBar(123);
foo.setBar(456);
});
it("tracks that the spy was called", function() {
expect(foo.setBar).toHaveBeenCalled();
});
it("tracks all the arguments of its calls", function() {
expect(foo.setBar).toHaveBeenCalledWith(123);
expect(foo.setBar).toHaveBeenCalledWith(456);
});
it("stops all execution on a function", function() {
expect(bar).toBeNull();
});
});
So how to run unit tests?
• Browser
• Test runner
– Karma
– Testem
Karma
• Runs tests in background in different
browsers
• Once code is changed on file system
reruns tests automatically
• Runs from the console
• Is integrated with IDE (WebStorm, VS)
• Requires NodeJS to be installed
Karmaconfiguration
• Install nodejs
• npm install -g karma
• npm install -g karma-cli
• Additional packs:
– karma-jasmine
– karma-junit-reporter
– karma-ng-scenario – e2e testing
– karma-ng-html2js-preprocessor – load all
templates and do not load them from server
– karma-phantomjs-launcher
Karmaconfiguration
Sample: http://jsfiddle.net/gdn0jocf/
• Doc: http://karma-
runner.github.io/0.8/config/configuratio
n-file.html
How to run it?
• Command line: karma start
configfilename
• Grunt task grunt task
DEMO
Unit testcontrollersample
describe('Home controller test', function () {
//loading module where controller is defined
beforeEach(module('app.home'));
//declaring variables that will be used in the tests
var controller, scope, deferred;
//creating items
beforeEach(inject(function ($rootScope, $controller, $q) {
deferred = $q.defer();
scope = $rootScope.$new();
//create the controller injecting the scope and the mocked service
controller = $controller('Home', {
$scope: scope,
DashboardService: {
getDashboard: function () {
return deferred.promise;
}
}
});
}));
//once result is not returned let's check that initial data state is correct
it('verifies NewMessagesCount is undefined', function () {
expect(controller.NewMessagesCount === undefined);
});
//Let's resolve value and see if it is correct
it('verifies NewMessagesCount is correct', function () {
deferred.resolve({ NewMessagesCount: 5 });
expect(controller.NewMessagesCount === 5);
});
it('verifies that scope contains go and it is a function', function () {
expect(scope.go === 'function');
});
});
Unit testservicesample
describe('Dashboard factory tests', function () {
//injecting module
beforeEach(module('app.services'));
//mocking dependcies
beforeEach(function () {
var Utility = {};
module(function ($provide) {
$provide.value('Utility', Utility);
});
});
var httpBackend, Factory;
//injecting httpBackend for testing of http
//injecting factory itself
beforeEach(inject(function ($httpBackend, Factory) {
httpBackend = $httpBackend;
Factory = Factory;
}));
it('checks that object is not modified by service and proper API method is called',
function () {
//setting method we expect to be called and method response
httpBackend.expectGET('api/Dashboard/').respond("Test");
var result = Factory.getDashboard();
//Verifying that all expected methods were called
httpBackend.flush();
//verifying that result is returned as expected
expect(result == "Test");
});
afterEach(function () {
httpBackend.verifyNoOutstandingExpectation();
httpBackend.verifyNoOutstandingRequest();
});
});
Unit teste2e sample
describe(
‘Angular App',
function () {
describe(‘Angular libraries list',
function () {
beforeEach(function () {
browser().navigateTo('/app/index.html');
});
it(
'should filter the list as user types into the search box',
function () {
expect(repeater('.users li').count()).toBe(5);
input('query').enter(‘angular-ui');
expect(repeater('.users li').count()).toBe(1);
input('query').enter('');
expect(repeater('.users li').count()).toBe(5);
}
);
} );});
Unit testing in JavaScript with Jasmine and Karma

Unit testing in JavaScript with Jasmine and Karma

  • 1.
  • 2.
    Overview • Unit testingframeworks • Jasmine (in details) • Test runners • Karma (in details) • Angular mocks • Testing controllers • Testing services
  • 3.
    Unit testing frameworks •Jasmine – Exposes BDD no additional set up and configuration required • Mocha – Requires additional configuration can work as TDD or BDD. Normally is being combined with Chai • QUnit
  • 4.
    Jasmine • Requires lesssetup • Is integrated with most CI • Is supported by test runners or can run from browser • Is fully BDD • Has built in assertion library • Does not have built in mocking frameworks(works fine with 3rd party like Squire or angular-mocks) • The syntax is really good
  • 5.
    Mocha • Requires moresetup • Is not fully integrated CI • Although can be executed via test runners or CI plugins • Provides ability to choose between TDD or BDD • Works fine with 3rd party assertion and mocking libraries • Is integrated with IDE(Web Storm) • Testing async is smooth
  • 6.
    Jasmineshortest testsample //describe functionfor the test suite describe("This is test suite", function() { //it function for the spec it("contains spec with an expectation", function() { //expect assertion function expect(true) //toBe is a matcher function .toBe(true); }); });
  • 7.
    Jasminetest suite • Isdone with describe function • describe expect as a first argument string with test suite description as a second function to be called to process test suite • Can be nested Test suite is a collection of test cases that are intended to be used to test a software program to show that it has some specified set of behaviors. A test suite often contains detailed instructions or goals for each collection of test cases and information on the system configuration to be used during testing. Wiki (c)
  • 8.
    Jasminetest spec • Isdone with it function • it expect as a first argument string with test suite description as a second function to be called to process test suite • Contain expectations
  • 9.
    Jasmineexpectations • Expectations arebuilt with the function expect which takes a value, called the actual. It is chained with a Matcher function, which takes the expected value. expect(true).toBe(true); expect(true).not.toBe(false);
  • 10.
    Matcherfunctions • toBe() • toEqual() •toMatch() • toBeDefined() • toContain() • toBeGreaterThan() • toBeNull() • And others • You can create custom matchers as well • Useful library jasmine-matchers
  • 11.
    JasmineTearUpandTearDown • beforeEach –tear up • afterEach – tear down describe("A spec (with setup and tear-down)", function() { var foo = 0; //will add 1 before each spec beforeEach(function() { foo += 1; }); //will set it to 0 after each spec afterEach(function() { foo = 0; }); //2 specs will verify that foo is equal to 1 it("is just a function, so it can contain any code", function() { expect(foo).toEqual(1); }); it("can have more than one expectation", function() { expect(foo).toEqual(1); }); });
  • 12.
    Jasminespies • At thevery high level can be treated as mocks • Can mock the call and record passed parameters • Can return fake values • Can mock the call and pass through to real function spyOn(foo, "getBar").and.returnValue(745); spyOn(foo, 'getBar').and.callThrough(); spyOn(foo, 'setBar');
  • 13.
    Jasminespies describe("Spy sample", function(){ var foo, bar = null; beforeEach(function() { foo = { setBar: function(value) { bar = value; } }; //spy on set bar method spyOn(foo, 'setBar'); foo.setBar(123); foo.setBar(456); }); it("tracks that the spy was called", function() { expect(foo.setBar).toHaveBeenCalled(); }); it("tracks all the arguments of its calls", function() { expect(foo.setBar).toHaveBeenCalledWith(123); expect(foo.setBar).toHaveBeenCalledWith(456); }); it("stops all execution on a function", function() { expect(bar).toBeNull(); }); });
  • 14.
    So how torun unit tests? • Browser • Test runner – Karma – Testem
  • 15.
    Karma • Runs testsin background in different browsers • Once code is changed on file system reruns tests automatically • Runs from the console • Is integrated with IDE (WebStorm, VS) • Requires NodeJS to be installed
  • 16.
    Karmaconfiguration • Install nodejs •npm install -g karma • npm install -g karma-cli • Additional packs: – karma-jasmine – karma-junit-reporter – karma-ng-scenario – e2e testing – karma-ng-html2js-preprocessor – load all templates and do not load them from server – karma-phantomjs-launcher
  • 17.
    Karmaconfiguration Sample: http://jsfiddle.net/gdn0jocf/ • Doc:http://karma- runner.github.io/0.8/config/configuratio n-file.html
  • 18.
    How to runit? • Command line: karma start configfilename • Grunt task grunt task DEMO
  • 19.
    Unit testcontrollersample describe('Home controllertest', function () { //loading module where controller is defined beforeEach(module('app.home')); //declaring variables that will be used in the tests var controller, scope, deferred; //creating items beforeEach(inject(function ($rootScope, $controller, $q) { deferred = $q.defer(); scope = $rootScope.$new(); //create the controller injecting the scope and the mocked service controller = $controller('Home', { $scope: scope, DashboardService: { getDashboard: function () { return deferred.promise; } } }); })); //once result is not returned let's check that initial data state is correct it('verifies NewMessagesCount is undefined', function () { expect(controller.NewMessagesCount === undefined); }); //Let's resolve value and see if it is correct it('verifies NewMessagesCount is correct', function () { deferred.resolve({ NewMessagesCount: 5 }); expect(controller.NewMessagesCount === 5); }); it('verifies that scope contains go and it is a function', function () { expect(scope.go === 'function'); }); });
  • 20.
    Unit testservicesample describe('Dashboard factorytests', function () { //injecting module beforeEach(module('app.services')); //mocking dependcies beforeEach(function () { var Utility = {}; module(function ($provide) { $provide.value('Utility', Utility); }); }); var httpBackend, Factory; //injecting httpBackend for testing of http //injecting factory itself beforeEach(inject(function ($httpBackend, Factory) { httpBackend = $httpBackend; Factory = Factory; })); it('checks that object is not modified by service and proper API method is called', function () { //setting method we expect to be called and method response httpBackend.expectGET('api/Dashboard/').respond("Test"); var result = Factory.getDashboard(); //Verifying that all expected methods were called httpBackend.flush(); //verifying that result is returned as expected expect(result == "Test"); }); afterEach(function () { httpBackend.verifyNoOutstandingExpectation(); httpBackend.verifyNoOutstandingRequest(); }); });
  • 21.
    Unit teste2e sample describe( ‘AngularApp', function () { describe(‘Angular libraries list', function () { beforeEach(function () { browser().navigateTo('/app/index.html'); }); it( 'should filter the list as user types into the search box', function () { expect(repeater('.users li').count()).toBe(5); input('query').enter(‘angular-ui'); expect(repeater('.users li').count()).toBe(1); input('query').enter(''); expect(repeater('.users li').count()).toBe(5); } ); } );});