Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Unit testing in JavaScript with Jasmine and Karma
-
Upload
andrey-kolodnitsky -
Category
Technology
-
view
213 -
download
0
Transcript of Unit testing in JavaScript with Jasmine and Karma
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
Karma configuration
Sample: http://jsfiddle.net/gdn0jocf/• Doc: http
://karma-runner.github.io/0.8/config/configuration-file.html
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); } ); } );});