Joe Karlsson
progress. tech. cats. coffee. art. food. photog. mpls.
The idea that you write tests first, then you write code.
As a result, you think about how you will use the code before you implement it.
assert(isEven(2), true)
function isEven(n) {
return n % 2 === 0;
}
FAIL
PASS
Unit tests should be specific, and so should the code to make the test pass.
Once it passes, refactor, and move on to the next test.
Mocha is a feature-rich JavaScript testing framework that runs on both Node and in the browser.
describe('add()', function () {
it('should add two numbers together', function () {
expect(add(1, 2)).to.equal(3);
});
it('should not concatenate a string and a number together', function() {
expect(add("1", 2)).to.not.equal("12");
});
});
$ mocha
function add(x, y) {
return x + y;
}
Why doesn't this pass all the tests?!
describe('Suite', function () {
it('should do something', function () {
// Test code goes here.
});
it('should do more things', function() {
// More test code goes here.
});
});
There are two important functions when writing tests:
describe() – Groups test cases into test suites.
Hooks allow you to set up both the state before and after your tests run.
describe('hooks', function() {
before(function() {
// runs before all tests in this block
});
after(function(){
// runs after all tests in this block
});
beforeEach(function(){
// runs before each test in this block
});
afterEach(function(){
// runs after each test in this block
});
// test cases
})
describe('fillArray', function () {
var array;
beforeEach(function () {
array = []; // Reset the array before each test runs.
});
it('should fill an array with a value, n-times', function () {
fillArray(array, "Hello", 3);
expect(array).to.deep.equal(["Hello", "Hello", "Hello"]);
});
it('should only fill a positive amount of times', function() {
fillArray(array, "Hi", -1);
expect(array).to.be.empty;
});
});
Let's take a look at the beforeEach() hook, which resets the array before each test case is ran.
Sometimes it's useful to skip tests when you don't know how to implement a test, but know it needs to be done.
describe('shuffleArray', function() {
it.skip('should be sorted in random order');
});
Text
Automatically runs tests whenever a file is changed.
$ mocha --watch
An assertion library for node and the browser that can be paired with any JavaScript testing framework.
describe('add()', function() {
it('should add two numbers together', function(){
var sum = add(4, 2);
expect(sum).to.equal(6);
});
});
Chai!
Extends each object with a should property to start your assertion chain.
var foo = 'bar',
beverages = {tea: [ 'chai', 'matcha', 'oolong']};
foo.should.be.a('string');
foo.should.equal('bar');
foo.should.have.length(3);
beverages.should.have.property('tea').with.length(3);
Chai provides an expect() function which lets you start your assertion chain.
var foo = 'bar',
beverages = {tea: [ 'chai', 'matcha', 'oolong']};
expect(foo).to.be.a('string');
expect(foo).to.equal('bar');
expect(foo).to.have.length(3);
expect(beverages).to.have.property('tea').with.length(3);
Unlike the should property, the expect function works on values that may be undefined.
Sometimes assertions can be difficult to understand unless you look at the actual test.
describe('turnOn()', function () {
var lightbulb;
before(function () {
lightbulb = { isOn: false };
});
it('should turn on a lightbulb', function () {
turnOn(lightbulb);
expect(lightbulb.isOn).to.be.true;
});
});
What is this false value?
expect() allows us to pass in a string to help tests easier to understand at a glance.
describe('turnOn()', function () {
var lightbulb;
before(function () {
lightbulb = { isOn: false };
});
it('should turn on a lightbulb', function () {
turnOn(lightbulb);
expect(lightbulb.isOn, 'lightbulb.isOn should be true').to.be.true;
});
});
You may have noticed that these tests read a lot like English.
There are some words Chai provides to "chain" assertions together so that they are easy to read.
These mean the exact same thing:
expect(1).to.equal(1);
expect(1).equal(1);
expect(1).to.be.that.which.is.to.equal(1);
Checking for equality between objects and arrays can be tricky in JavaScript.
Luckily, Chai provides us with deep.equal (or eql), which compares each value inside objects and arrays for us.
var myObject = { name: "Mocha" };
expect(myObject).to.deep.equal({ name: "Mocha" });
var myArray = [1, 2, 3];
expect(myArray).to.eql([1, 2, 3]);
There are many more ways to compare values than equality, please read the docs!
By Joe Karlsson
a devleague slide deck by Tony