+ All Categories
Home > Technology > Writing testable js [by Ted Piotrowski]

Writing testable js [by Ted Piotrowski]

Date post: 22-May-2015
Category:
Upload: javascript-meetup-hcmc
View: 437 times
Download: 3 times
Share this document with a friend
Description:
About us Author: Ted Piotrowski Find me at: [email protected] Sample code: https://bitbucket.org/tpiotrowski/js-hcm Presentation made for Javascript Ho Chi Minh City Meetup Group You can find us at: http://www.meetup.com/JavaScript-Ho-Chi-Minh-City/ https://www.facebook.com/JavaScriptHCMC https://plus.google.com/u/0/communities/116105314977285194967
Popular Tags:
26
Writing testable JS by Ted Piotrowski Javascript Ho Chi Minh City
Transcript
Page 1: Writing testable js [by Ted Piotrowski]

Writing testable JSby Ted Piotrowski

Javascript Ho Chi Minh City

Page 2: Writing testable js [by Ted Piotrowski]

Excuses for not testing

● I know the code● Test suite is hard to configure and run● You can’t test UI● You can’t unit test JS code

Page 3: Writing testable js [by Ted Piotrowski]

$(document).ready(function() {

$('#new-status form').submit(function(e) {

e.preventDefault();

$.ajax({

url: '/status',

type: 'POST',

dataType: 'json',

data: { text: $('#new-status').find('textarea').val() },

success: function(data) {

$('#statuses').append('<li>' + data.text + '</li>');

$('#new-status').find('textarea').val('');

}

});

});

});

source: https://github.com/kjbekkelund/writings/blob/master/published/understanding-backbone.md/

Page 4: Writing testable js [by Ted Piotrowski]

Documentation

● Impossible to write a good test without a good specification

● If you don’t have time to write a test, at least write documentation○ it will allow others to write tests later

Page 5: Writing testable js [by Ted Piotrowski]

/**

* adds two numbers together

*/

function sum(a, b)

assert(sum(1, 2), 3);

Page 6: Writing testable js [by Ted Piotrowski]

/**

* adds two numbers together

*/

function sum(a, b)

assert(sum(1, ‘a’), ?);

Page 7: Writing testable js [by Ted Piotrowski]

/**

* adds two numbers together,

* otherwise returns null

*/

function sum(a, b)

assert(sum(1, ‘a’), null);

Page 8: Writing testable js [by Ted Piotrowski]

Dependencies

● Can’t write good tests unless you understand what external objects the code depends on

● loose coupling● use requirejs, almond.js, squire.js● move dependencies up the call stack and

inject

Page 9: Writing testable js [by Ted Piotrowski]

Scope

● An assertion should only rely on the method being tested

● What is a “unit”?● is $(function() { }) a unit?

Page 10: Writing testable js [by Ted Piotrowski]

// Should we stub addTwo, addOne?

// When we limit scope, we forfeit integration

function addThree(a) {

var x = addTwo(a);

var y = addOne(x);

return y;

}

Page 11: Writing testable js [by Ted Piotrowski]

Testing with the DOM

● Use a DOM fragment / jQuery fragment● Inject it into the module constructor

Page 12: Writing testable js [by Ted Piotrowski]

function Word() {

this.el = $('.word'); // external dependency

}

Word.prototype.setText = function(text) {

this.el.text(text);

};

var word = new Word();

word.setText('Hello World');

assert(???, 'Hello World');

Page 13: Writing testable js [by Ted Piotrowski]

function Word(el) {

this.el = el; // dependency injection

}

Word.prototype.setText = function(text) {

this.el.text(text);

};

var mockEl = $('<div></div>'); // use a test double

var word = new Word(mockEl); // inject the dependency

word.setText('Hello World');

assert(mockEl.text(), 'Hello World');

Page 14: Writing testable js [by Ted Piotrowski]

function Word(el) {

this.el = el || $('.word'); // optional injection

}

Word.prototype.setText = function(text) {

this.el.text(text);

};

var mockEl = $('<div></div>');

var word = new Word(mockEl);

word.setText('Hello World');

assert(mockEl.text(), 'Hello World');

Page 15: Writing testable js [by Ted Piotrowski]

Dealing with window properties

● You code will likely touch Web API○ document, Math,

● Can use mocks and stubs for methods● Many Web API properties are read-only

Page 16: Writing testable js [by Ted Piotrowski]

// If your production code calls alert(), you can mock it

var spy = sinon.spy(window, "alert");

assert(spy.calledWith("My alert message"));

// However, you can't modify read only properties

Math.PI = 3.15; // won’t work

window.History.length = 12;

Page 17: Writing testable js [by Ted Piotrowski]

function Win(windowObj) {

this.window = windowObj || window;

}

Win.prototype.scrollX = function() { return this.window.scrollX };

Win.prototype.scrollY = function() { return this.window.scrollY };

var win = new Win(); // in production

// win.scrollX() => actual value

var win = new Win({ // in testing

scrollX: 50, scrollY: 40, History: { … }

}); // win.scrollX() => 50

Page 18: Writing testable js [by Ted Piotrowski]

Dealing with network calls

● Use sinon fake server

Page 19: Writing testable js [by Ted Piotrowski]

{

"test should fetch comments from server" : function () {

this.server.respondWith("GET", "/some/article/comments.json",

[200, { "Content-Type": "application/json" },

'[{ "id": 12, "comment": "Hey there" }]']);

var callback = sinon.spy();

myLib.getCommentsFor("/some/article", callback);

this.server.respond();

sinon.assert.calledWith(callback, [{ id: 12, comment: "Hey there" }]));

}

}

Page 20: Writing testable js [by Ted Piotrowski]

Code coverage

● Reports what lines of production JS are executed during testing

● necessary, but not sufficient● Istanbul is a good tool

○ integrates with Karma

Page 21: Writing testable js [by Ted Piotrowski]

JS integration tests

● main.js file initializes your components and injects DOM dependencies

● Stub your REST calls● Just like unit testing, user events are your

input, DOM changes are your output

Page 22: Writing testable js [by Ted Piotrowski]

// Bootstrap your application here

// Inject your DOM dependencies at top of call stack

// Allows you to mock/stub the DOM for each component

$(function() {

var $el = $('.some-element');

var component = new Component($el);

var $el2 = $('.some-element2');

var component2 = new Component($el2);

// initialize more components, global state here

});

Page 23: Writing testable js [by Ted Piotrowski]

Demo time

Page 25: Writing testable js [by Ted Piotrowski]

About usAuthor: Ted PiotrowskiFind me at: [email protected] code: https://bitbucket.org/tpiotrowski/js-hcm

Presentation made for Javascript Ho Chi Minh City Meetup Group

You can find us at:● http://www.meetup.com/JavaScript-Ho-Chi-Minh-City/● https://www.facebook.com/JavaScriptHCMC● https://plus.google.com/u/0/communities/116105314977285194967● http://www.slideshare.net/JavascriptMeetup

Page 26: Writing testable js [by Ted Piotrowski]

Lean Coffee

Discussion topics


Recommended