Technology Previews and Proposals
To examine unit testing options, discuss their pros and cons, and work towards a decision on which tool to use.
A software development process in which the smallest testable parts of an application, called units, are individually and independently scrutinized for proper operation.
Small, focused tests on isolated functions or functionality
Meant to be fast and help isolate bugs
describe("Player", function() {
var player;
var song;
beforeEach(function() {
player = new Player();
song = new Song();
});
it("should be able to play a Song", function() {
player.play(song);
expect(player.currentlyPlayingSong).toEqual(song);
//demonstrates use of custom matcher
expect(player).toBePlaying(song);
});
//...
});
beforeEach(function() {
this.addMatchers({
toBePlaying: function(expectedSong) {
var player = this.actual;
return player.currentlyPlayingSong === expectedSong &&
player.isPlaying;
}
});
});
spec-helper.js
player.spec.js
describe("Player", function() {
var player;
var song;
// ...
describe("when song has been paused", function() {
beforeEach(function() {
player.play(song);
player.pause();
});
it("should indicate that the song is currently paused", function() {
expect(player.isPlaying).toBeFalsy();
// demonstrates use of 'not' with a custom matcher
expect(player).not.toBePlaying(song);
});
it("should be possible to resume", function() {
player.resume();
expect(player.isPlaying).toBeTruthy();
expect(player.currentlyPlayingSong).toEqual(song);
});
});
// ...
});
describe("Player", function() {
var player;
var song;
// ...
// demonstrates use of spies to intercept and test method calls
it("tells the current song if the user has made it a favorite", function() {
spyOn(song, 'persistFavoriteStatus');
player.play(song);
player.makeFavorite();
expect(song.persistFavoriteStatus).toHaveBeenCalledWith(true);
});
//demonstrates use of expected exceptions
describe("#resume", function() {
it("should throw an exception if song is already playing", function() {
player.play(song);
expect(function() {
player.resume();
}).toThrow("song is already playing");
});
});
});
$('#header').should.have.attr('foo');
expect($('body')).to.have.attr('foo', 'bar');
expect($('body')).to.have.attr('foo').match(/bar/);
$('#header').should.have.prop('disabled');
expect($('body')).to.have.prop('disabled', false);
expect($('body')).to.have.prop('value').match(/bar/);
function getTodos(listId, callback) {
jQuery.ajax({
url: "/todo/" + listId + "/items",
success: function (data) {
// Node-style CPS: callback(err, data)
callback(null, data);
}
});
}
after(function () {
// When the test either fails or passes, restore the original
// jQuery ajax function (Sinon.JS also provides tools to help
// test frameworks automate clean-up like this)
jQuery.ajax.restore();
});
it("makes a GET request for todo items", function () {
sinon.stub(jQuery, "ajax");
getTodos(42, sinon.spy());
assert(jQuery.ajax.calledWithMatch({ url: "/todo/42/items" }));
});
var test = require('tape');
test('timing test', function (t) {
t.plan(2);
t.equal(typeof Date.now, 'function');
var start = Date.now();
setTimeout(function () {
t.equal(Date.now() - start, 100);
}, 100);
});
$ node example/timing.js
TAP version 13
# timing test
ok 1 should be equal
not ok 2 should be equal
---
operator: equal
expected: 100
actual: 107
...
1..2
# tests 2
# pass 1
# fail 1
Tap Output
define(function (require) {
var tdd = require('intern!tdd');
tdd.suite('Suite name', function () {
tdd.before(function () {
// executes before suite starts
});
tdd.after(function () {
// executes after suite ends
});
tdd.beforeEach(function () {
// executes before each test
});
tdd.afterEach(function () {
// executes after each test
});
tdd.test('Test foo', function () {
// a test case
});
});
define(function (require) {
var tdd = require('intern!tdd');
tdd.suite('Suite name', function () {
tdd.before(function () {
// executes before suite starts
});
tdd.after(function () {
// executes after suite ends
});
tdd.beforeEach(function () {
// executes before each test
});
tdd.afterEach(function () {
// executes after each test
});
tdd.test('Test foo', function () {
// a test case
});
});
define(function (require) {
var bdd = require('intern!bdd');
bdd.describe('the thing being tested', function () {
bdd.before(function () {
// executes before suite starts
});
bdd.after(function () {
// executes after suite ends
});
bdd.beforeEach(function () {
// executes before each test
});
bdd.afterEach(function () {
// executes after each test
});
bdd.it('should do foo', function () {
// a test case
});
});
});