+ All Categories
Home > Technology > Intro to JavaScript Testing

Intro to JavaScript Testing

Date post: 28-Jan-2015
Category:
Upload: ran-mizrahi
View: 128 times
Download: 4 times
Share this document with a friend
Description:
 
Popular Tags:
32
Introduction to JavaScript Testing Ran Mizrahi (@ranm8) Open Source Dpt. Leader @ CodeOasis Saturday, April 27, 13
Transcript
Page 1: Intro to JavaScript Testing

Introduction to JavaScript Testing

Ran Mizrahi (@ranm8)Open Source Dpt. Leader @ CodeOasis

Saturday, April 27, 13

Page 2: Intro to JavaScript Testing

About CodeOasis

• CodeOasis specializes in cutting-edge web solutions.

• Large variety of customers (from startups to enterprises).

• Technologies we love:

• PHP - Symfony2 and Drupal• node.js • HTML5• CSS3• AngularJS

• Our Microsoft department works with C#, WPF, etc.

Saturday, April 27, 13

Page 3: Intro to JavaScript Testing

Why Do Software Projects Fail?!

• Deliver late or over budget.

• Deliver the wrong thing.

• Unstable in production.

Production Maintenance

• Expensive maintenance.

• Long adjustment to market needs.

• Long development cycles.

Saturday, April 27, 13

Page 4: Intro to JavaScript Testing

Why Do Software Projects Fail?!

Saturday, April 27, 13

Page 5: Intro to JavaScript Testing

Untestable code...function createUser(properties) { var user = { firstName: properties.firstName, lastName: properties.lastName, username: properties.username, mail: properties.mail }; var fullName = User.firstName + ' ' + User.lastName;

// Make sure user is valid if (!user.firstName || !user.lastName) { throw new Error('First or last name are not valid!'); } else if(typeof user.mail === 'string' && user.mail.match(new RegExp(/^\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,3}$/)) === null) { throw new Error('Mail is not valid'); } else if (!user.username) { throw new Error('Username is not valid'); }

$.post('/user', { fullName: fullName, userName: user.username, mail: user.mail }, function(data) { var message; if (data.code === 200) { message = 'User saved successfully!'; } else { message = 'Operation was failed!'; }

$('#some-div').animate({ 'margin-left': $(window).width() }, 1000, function() { $(this).html(message); }); });}

Saturday, April 27, 13

Page 6: Intro to JavaScript Testing

Why Test Your Code???The problems with untestable code:

• Tightly coupled.

• No separation of concerns.

• Not readable.

• Not predictable.

• Global states.

• Long methods.

• Large classes/objects.

Saturday, April 27, 13

Page 7: Intro to JavaScript Testing

Why Test Your Code???The problems with untestable code:

• Tightly coupled.

• No separation of concerns.

• Not readable.

• Not predictable.

• Global states.

• Long methods.

• Large classes/objects.

>

• Hard to maintain.

• High learning curve.

• Stability issues.

• You can never expect problems before they occur

Saturday, April 27, 13

Page 8: Intro to JavaScript Testing

Test-Driven Development To The Recuse!

Methodology for using automated unit tests to drive software design, quality

and stability.

Saturday, April 27, 13

Page 9: Intro to JavaScript Testing

Test-Driven Development To The Recuse!

How it’s done :

• First the developer writes a failing test case that defines a desired functionality to the software.

• Makes the code pass those tests.

• Refactor the code to meet standards.

Saturday, April 27, 13

Page 10: Intro to JavaScript Testing

Seems Great But How Much Longer Does TDD Takes???

My experience:• Initial progress will be slower.• Greater consistency.• Long tern cost is drastically

lower• After getting used to it, you

can write TDD faster (-:

Studies:• Takes 15-30% longer.• 45-80% less bugs.• Fixing bugs later on is

dramatically faster.

Saturday, April 27, 13

Page 11: Intro to JavaScript Testing

The Three Rules of TDD

Rule #1Your code should always fail before you implement the code

Rule #2Implement the simplest code possible to pass your tests.

Rule #3Refactor, refactor and refractor - There is no shame in refactoring.

Saturday, April 27, 13

Page 12: Intro to JavaScript Testing

BDD (Behavior-Driven Development)

Test-Driven Development

Saturday, April 27, 13

Page 13: Intro to JavaScript Testing

BDD (Behavior-Driven Development)

Test-Driven Development

What exactly are we testing?!

Saturday, April 27, 13

Page 14: Intro to JavaScript Testing

BDD (Behavior-Driven Development)

• Originally started in 2003 by Dan North, author of JBehave, the first BDD tool.

• Based on the TDD methodology.

• Aims to provide tools for both developers and business (e.g. product manager, etc.) to share development process together.

• The steps of BDD :• Developers and business personas write specification together.• Developer writes tests based on specs and make them fail.• Write code to pass those tests.• Refactor, refactor, refactor...

Saturday, April 27, 13

Page 15: Intro to JavaScript Testing

BDD (Behavior-Driven Development)

Feature: ls In order to see the directory structure As a UNIX user I need to be able to list the current directory's contents

Scenario: List 2 files in a directory Given I am in a directory "test" And I have a file named "foo" And I have a file named "bar" When I run "ls" Then I should get: """ bar foo """

Saturday, April 27, 13

Page 16: Intro to JavaScript Testing

Main Test Types

• Unit Testing

• Integration Testing

• Functional Testing

Saturday, April 27, 13

Page 17: Intro to JavaScript Testing

Challenges Testing JavaScript

• Async tests:

• Testing async methods can be tricky.• Define tests timeout.• Indicate when test is completed in callback.• Assert on callback.

• DOM:

• Testing DOM is a difficult task.• The key is to separate your controller and model logic from

DOM and test those only.• Testing DOM is done using functional testing (e.g. WebDriver,

etc.)

Saturday, April 27, 13

Page 18: Intro to JavaScript Testing

TDD/BDD using Mocha and Expect.js

Mocha is a feature-rich JavaScript test frameworks running on node and the browser, making asynchronies tests easy.

Mocha

Main features:

• Supports both TDD and BDD styles.

• Both browser and node support.

• Proper exit status for CI support.

• node.js debugger support.

• Highly flexible, choose and join the pieces yourself (spy library, assertion library, etc.).

Saturday, April 27, 13

Page 19: Intro to JavaScript Testing

TDD/BDD using Mocha and Expect.js

Expect.js is a minimalistic assertion library based on should.js Expect.js

Main features:

• BDD style.

• Compatible with all test frameworks.

• Both node.js and browser compatible.

• Standalone assertion library.

Saturday, April 27, 13

Page 20: Intro to JavaScript Testing

TDD/BDD using Mocha and Expect.js

Installing Mocha and Expect.js

$ npm install mocha -g

$ npm install expect.js -g

Install mocha globally using npm:

Install Expect.js:

Saturday, April 27, 13

Page 21: Intro to JavaScript Testing

TDD/BDD using Mocha and Expect.js

var expect = require('expect.js');

describe('Array', function() { describe('#indexOf()', function() { it('Expect -1 when the value is not present', function() { var array = [1, 2, 3]; expect(array.indexOf(4)).to.be(-1); }); });});

“Normal” test:

Run it..$ mocha --reporter spec Array #indexOf() ✓ Expect -1 when the value is not present

1 test complete (5 ms)

Saturday, April 27, 13

Page 22: Intro to JavaScript Testing

TDD/BDD using Mocha and Expect.js“Async” test:var expect = require('expect.js');

function asyncCall(val ,callback) { var prefix = ' - ';

setTimeout(function() { var newString = val + prefix + 'OK';

callback(newString); }, 500);}

describe('asyncCall', function() { it('Add suffix that prefixed with - to the given string', function(done) { var testVal = 'Foo';

asyncCall(testVal, function(response) { expect(response).to.contain(testVal + ' - OK'); done(); }); });});

Let’s run it...

Saturday, April 27, 13

Page 23: Intro to JavaScript Testing

Back to our code

Saturday, April 27, 13

Page 24: Intro to JavaScript Testing

First, Let’s Write The Tests!function createUser(properties) { var user = { firstName: properties.firstName, lastName: properties.lastName, username: properties.username, mail: properties.mail }; var fullName = User.firstName + ' ' + User.lastName;

// Make sure user is valid if (!user.firstName || !user.lastName) { throw new Error('First or last name are not valid!'); } else if(typeof user.mail === 'string' && user.mail.match(new RegExp(/^\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,3}$/)) === null) { throw new Error('Mail is not valid'); } else if (!user.username) { throw new Error('Username is not valid'); }

$.post('/user', { fullName: fullName, userName: user.username, mail: user.mail }, function(data) { var message; if (data.code === 200) { message = 'User saved successfully!'; } else { message = 'Operation was failed!'; }

$('#some-div').animate({ 'margin-left': $(window).width() }, 1000, function() { $(this).html(message); }); });}

Saturday, April 27, 13

Page 25: Intro to JavaScript Testing

First, Let’s Write The Tests!

What to test in our case:

• Validations.

• Full name getter.

• User save callback

What not to test :

• DOM manipulations - for that, we should use functional testing for that cause (e.g. WebDriver)

• AJAX requests - Leaving integration testing aside.

Saturday, April 27, 13

Page 26: Intro to JavaScript Testing

First, Let’s Write The Tests!describe('User', function() { var user;

beforeEach(function() { // Create the user obj user = new User({ firstName: 'Ran', lastName: 'Mizrahi', mail: '[email protected]', username: 'ranm' }); });

afterEach(function() { // clean-up user = {}; });

describe('#fullName()', function() { it('Should return firstName and lastName separated by space', function() { expect(user.fullName).to.be('Ran Mizrahi'); }); });

describe('#save()', function() { it('Should save user without any errors', function(done) { user.save(function(error) { if (error) { throw error; } else { done(); } }); }); });

describe('#mail()', function() { it('Should set mail correctly after mail validation', function() { expect(user.mail).to.be('[email protected]'); }); });});

Saturday, April 27, 13

Page 27: Intro to JavaScript Testing

Run those tests

Saturday, April 27, 13

Page 28: Intro to JavaScript Testing

Now, Let’s Write The Codevar User = (function() { 'use strict';

var User = function(properties) { // Set some data this.firstName = properties.firstName || ''; this.lastName = properties.lastName || ''; this.username = properties.username || ''; this.mail = properties.mail || ''; };

User.__defineGetter__('fullName', function() { return this.firstName + ' ' + this.lastName; });

User.__defineSetter__('mail', function(mail) { var matcher = new RegExp(/^\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,3}$/);

if (mail.match(matcher) === null) { throw 'Mail is not valid'; }

this._mail = mail; });

User.prototype.save = function(callback) { setTimeout(function() { callback(); }, 1000);

return this; };

return User;}());

Saturday, April 27, 13

Page 29: Intro to JavaScript Testing

Run those tests, again!

Saturday, April 27, 13

Page 30: Intro to JavaScript Testing

Running The Tests

mocha tests can run in different environments and formats:

• Browser - using mocha.js (see example)• For CI automation use JSTestDriver.

• CLI - as demonstrated before using the “mocha” command.

• CI (e.g. xunit) - $ mocha test/asyncTest.js --reporter xunit.

• Many other formats (JSON, HTML, list, Spec, etc.)

Saturday, April 27, 13

Page 31: Intro to JavaScript Testing

Benefits of Testing Your Code

• Short feedback/testing cycle.

• High code coverage of tests that can be at run any time to provide feedback that the software is functioning.

• Provides detailed spec/docs of the application.

• Less time spent on debugging and refactoring.

• Know what breaks early on.

• Enforces code quality (decoupled) and simplicity.

• Help you focus on writing one job code units.

Saturday, April 27, 13

Page 32: Intro to JavaScript Testing

Questions?Thank you!

Saturday, April 27, 13


Recommended