unit testing in javascript with jasmine and karma

22
Unit testing

Upload: andrey-kolodnitsky

Post on 24-Jul-2015

213 views

Category:

Technology


0 download

TRANSCRIPT

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

Jasmine shortest test sample

//describe function for the test suitedescribe("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);

});});

Jasmine test 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)

Jasmine test 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

Jasmine expectations

• 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);

Matcher functions

• toBe() • toEqual() • toMatch() • toBeDefined() • toContain() • toBeGreaterThan() • toBeNull()• And others• You can create custom matchers as well• Useful library jasmine-matchers

Jasmine TearUp and TearDown

• 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); });});

Jasmine spies• 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');

Jasmine spiesdescribe("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

Karma configuration

• 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

How to run it?

• Command line: karma start configfilename

• Grunt task grunt task

DEMO

Unit test controller sampledescribe('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 test service sampledescribe('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 test e2e sampledescribe( ‘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); } ); } );});