unit testing front end javascript

Post on 05-Dec-2014

321 Views

Category:

Internet

3 Downloads

Preview:

Click to see full reader

DESCRIPTION

Unit Testing Front End JavaScript with Yuri Takhteyev Presented on September 18 2014 at FITC's Web Unleashed Toronto 2014 Conference More info at www.fitc.ca Building complex software application can be made much easier with unit testing – a fact well established in back-end work but often overlooked on the front-end. Yuri Takhteyev will look at some of the tools and techniques for unit testing front end code, focusing on Mocha and Karma. Most of the examples will draw on AngularJS but the main ideas are applicable to other frameworks as well. OBJECTIVE Learn how to write unit tests for front-end code. TARGET AUDIENCE Front-end JavaScript developers not currently using unit testing or those experiencing difficulties with unit testing. ASSUMED AUDIENCE KNOWLEDGE Intermediate front-end JavaScript, no prior experience with front-end unit testing FIVE THINGS AUDIENCE MEMBERS WILL LEARN How unit testing benefits the developer How to structure applications to make them testable How to use Mocha and Karma in unit testing How to mock dependencies (and why) How to handle asynchronous code

TRANSCRIPT

UNIT TESTING FRONT END JAVASCRIPT

YURI TAKHTEYEV

@QARAMAZOV@RANGLEIO

Why Bother with Unit Tests?

Why Bother with Unit Tests?

TDD Lite

Writing Testable Code

☛ Modular code

☛ AngularJS

services

☛ Other modules not entangled with DOM

Keeping Tests Simple

Common Tools

Runner: KarmaTask Automation: Gulp || GruntScorer: Mocha || JasmineAssertions: Chai || JasmineSpies: Sinon || Jasmin

+ CI tools (e.g. Magnum-CI)

http://yto.io/xunit

Installing the Example Code

# First installgit clone https://github.com/yuri/webu-unit.gitcd webu-unitnpm installsudo npm install -g gulpsudo npm install -g bowerbower install

# Now rungulp karma

☛ You’ll need to install git and node before

A Basic Testfunction isOdd(value) { return (value % 2 === 1);}

describe('isEven', function () { it('should handle positive ints', function () { if (isOdd(2)) { throw new Error('2 should be even'); } });});

☛ Let’s put this in “client/app/is-odd.test.js”

Chaidescribe('isEven', function () { it('should handle positive ints', function () { expect(isOdd(1)).to.be.true; expect(isOdd(2)).to.be.false; expect(isOdd(3)).to.be.true; });});

☛ More Chai at http://chaijs.com/api/bdd/

Extending Testsdescribe('isEven', function () { ... it('should handle negative ints', function () { expect(isOdd(-1)).to.be.true; });});

Extending Testsdescribe('isEven', function () { ... xit('should handle negative ints', function () { expect(isOdd(-1)).to.be.true; });});

Extending Testsdescribe('isEven', function () { ... it.only('should handle negative ints', function () { expect(isOdd(-1)).to.be.true; });});

Extending Testsdescribe('isEven', function () { ... it('should handle negative ints', function () { expect(isOdd(-1)).to.be.true; });});

function isOdd(value) { return (value % 2 === 1);}

Testing a Serviceangular.module('app.tasks', [ 'app.server'])

.factory('tasks', function(server) { var service = {};

service.getTasks = function () { return server.get('tasks'); };

return service;});

☛ Let’s put this in “client/app/tasks-service.js”

The Test, Take 1describe('tasks service', function () { beforeEach(module('app.tasks')); it('should get tasks', function() { var tasks = getService('tasks'); expect(tasks.getTasks()).to .not.be.undefined; });});

☛ Let’s put this in “client/app/tasks-service.test.js”

Error: [$injector:unpr] Unknown provider:serverProvider <- server <- tasks

☛ See “client/testing/test-utils.js” for implementation of getService().

Mocking Dependenciesvar data;beforeEach(module(function($provide){ $provide.service('server', function() { return { get: function() { return Q.when(data); } }; }); $provide.service('$q', function() { return Q; });}));

Chrome 37.0.2062 (Mac OS X 10.9.4): Executed 3 of 3 SUCCESS (0.046 secs / 0.027 secs)

Let’s Extend the Serviceservice.getMyTasks = function () { return server.getTasks() .then(function(taskArray) { return _.filter(taskArray, function(task) { return task.owner === user.userName; }); });};

☛ We’ll need to inject “user” into the service

Mocking the User$provide.service('user', function() { return { username: 'yuri' };});

☛ The mock can be very simple

An Async Test, Wrongit('should get user\'s tasks', function() { var tasks = getService('tasks'); data = [{ owner: 'bob', description: 'Mow the lawn' }, { owner: 'yuri', description: 'Save the world' }]; tasks.getMyTasks() .then(function(myTasks) { expect(myTasks.length).to.equal(1); });});

☛ Always check that “wrong” tests fail!

An Async Test, Rightit('should get user\'s tasks', function() { var tasks = getService('tasks'); data = [{ owner: 'bob', description: 'Mow the lawn' }, { owner: 'yuri', description: 'Save the world' }]; return tasks.getMyTasks() .then(function(myTasks) { expect(myTasks.length).to.equal(1); });});

Spies with Sinon$provide.service('server', function() { return { get: sinon.spy(function() { return Q.when(data); }) };});

var server = getService('server');return tasks.getMyTasks() .then(function(myTasks) { expect(myTasks.length).to.equal(1); server.get.should.have.been.calledOnce; });

Thank You.Contact: yuri@rangle.io http://yto.io @qaramazov

This presentation: http://yto.io/xunit

top related