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: Karma Task Automation: Gulp || Grunt Scorer: Mocha || Jasmine Assertions: Chai || Jasmine Spies: Sinon || Jasmin + CI tools (e.g. Magnum-CI)
http://yto.io/xunit
Installing the Example Code # First install git clone https://github.com/yuri/webu-unit.git cd webu-unit npm install sudo npm install -g gulp sudo npm install -g bower bower install # Now run gulp karma ☛ You’ll need to install git and node before
A Basic Test function 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”
Chai describe('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 Tests describe('isEven', function () { ... it('should handle negative ints', function () { expect(isOdd(-1)).to.be.true; }); });
Extending Tests describe('isEven', function () { ... xit('should handle negative ints', function () { expect(isOdd(-1)).to.be.true; }); });
Extending Tests describe('isEven', function () { ... it.only('should handle negative ints', function () { expect(isOdd(-1)).to.be.true; }); });
Extending Tests describe('isEven', function () { ... it('should handle negative ints', function () { expect(isOdd(-1)).to.be.true; }); }); function isOdd(value) { return (value % 2 === 1); }
Testing a Service angular.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 1 describe('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” ☛ See “client/testing/test-utils.js” for implementation of getService(). Error: [$injector:unpr] Unknown provider: serverProvider <- server <- tasks
Mocking Dependencies var 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 Service service.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, Wrong it('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, Right it('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
Image Credits by dunechaser by lincolnblues by spenceyc by creative_tools by mycroyance by angeljimenez by snre

Unit Testing Front End JavaScript

  • 1.
    UNIT TESTING FRONTEND JAVASCRIPT YURI TAKHTEYEV @QARAMAZOV @RANGLEIO
  • 2.
    Why Bother withUnit Tests?
  • 3.
    Why Bother withUnit Tests?
  • 4.
  • 5.
    Writing Testable Code ☛ Modular code ☛ AngularJS services ☛ Other modules not entangled with DOM
  • 6.
  • 7.
    Common Tools Runner:Karma Task Automation: Gulp || Grunt Scorer: Mocha || Jasmine Assertions: Chai || Jasmine Spies: Sinon || Jasmin + CI tools (e.g. Magnum-CI)
  • 8.
  • 9.
    Installing the ExampleCode # First install git clone https://github.com/yuri/webu-unit.git cd webu-unit npm install sudo npm install -g gulp sudo npm install -g bower bower install # Now run gulp karma ☛ You’ll need to install git and node before
  • 10.
    A Basic Test function 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”
  • 11.
    Chai describe('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/
  • 12.
    Extending Tests describe('isEven',function () { ... it('should handle negative ints', function () { expect(isOdd(-1)).to.be.true; }); });
  • 13.
    Extending Tests describe('isEven',function () { ... xit('should handle negative ints', function () { expect(isOdd(-1)).to.be.true; }); });
  • 14.
    Extending Tests describe('isEven',function () { ... it.only('should handle negative ints', function () { expect(isOdd(-1)).to.be.true; }); });
  • 15.
    Extending Tests describe('isEven',function () { ... it('should handle negative ints', function () { expect(isOdd(-1)).to.be.true; }); }); function isOdd(value) { return (value % 2 === 1); }
  • 16.
    Testing a Service angular.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”
  • 17.
    The Test, Take1 describe('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” ☛ See “client/testing/test-utils.js” for implementation of getService(). Error: [$injector:unpr] Unknown provider: serverProvider <- server <- tasks
  • 18.
    Mocking Dependencies vardata; 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)
  • 19.
    Let’s Extend theService service.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
  • 20.
    Mocking the User $provide.service('user', function() { return { username: 'yuri' }; }); ☛ The mock can be very simple
  • 21.
    An Async Test,Wrong it('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!
  • 22.
    An Async Test,Right it('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); }); });
  • 23.
    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; });
  • 24.
    Thank You. Contact: yuri@rangle.io http://yto.io @qaramazov This presentation: http://yto.io/xunit
  • 25.
    Image Credits bydunechaser by lincolnblues by spenceyc by creative_tools by mycroyance by angeljimenez by snre