Unit Testing with Mocha

Joshua Lacey
6 min readDec 19, 2017

Now that I know javascript I thought it was probably a good time to start getting into the habit of writing tests. It’s probably a good idea to abandon my old ways of waiting for something to break and then going down a rabbit hole trying to find where the problem started. I saw a lot of tests written using mocha and I decided to write out some tests myself to make sure that I really understood what they did.

Mocha is a javascript testing framework that runs on Node.js. It can be set up so that I can run npm test and it will run all of your mocha tests to check that my functions are doing what they are supposed to.

Basic setup

I think it makes the most sense to keep my test environment in my devDependencies so I’d say the best code to run is npm install --save-dev mocha chai . After that I create a folder in root directory of my project called test the test folder is a default folder for mocha. Next I’m going to add mocha to my test script in our package.json .

My packages.json at this point includes the following:

{
"name": "mocha-tests-demo",
"version": "1.0.0",
"description": "a demo for running mocha tests",
"main": "index.js",
"scripts": {
"test": "mocha"
},
"author": "Joshua Lacey",
"license": "ISC",
"devDependencies": {
"mocha": "^4.0.1",
"chai": "^4.1.2"
}
}

Now I create a test file in my test folder called index-test.js. This is where I’m going to write all of the tests for my functions.

What to test?

I recently saw this video by Mattias Petter Johansson where he talked about object composition vs inheritance. The main point being that when you inherit from a class you get a bunch of things you probably don’t need, where as with composition you can create factory functions which use the Object.assign method to compose and return constructed objects.

So I’m going to make a lesson for myself that helps me write out factory functions and make sure their results give me the correctly composed objects. I’m going to do this as a test driven development(TDD) process to make sure I can compose the correct objects using Object.assign().

Setting up the test file

First, at the top of our file, I require chai, then I’m going to assign it’s should and expect type assertions to their respective variables.

//test/test-index.jsconst chai = require('chai')
const should = chai.should()
const expect = chai.expect

Next I use the mocha’s describe function to define what it is that I’m going to be running tests on. I like to think of describe as a folder for all of my tests, I can even have sub describes like this:

describe('Animal', function(){//some tests that pertain to all animals   describe('Cat', function() {
//some tests in here specific to cats.
}
describe('Dog', function() {
//some tests in here specific to dogs.
}
describe('Snakes', function() {
//some tests in here specific to snakes.
}
})

If you watched the factory functions video from above you’d see that instead of creating a class and using the new keyword I’m going to create factory functions that will return an object every time it is called. The point there is to make our functions modular so that I can compose any type of animal I want and only apply the properties that make sense for it. This is were I make full use of TDD to make sure I’m not inheriting any of the wrong properties. Within my main description I am going to assign some constants that are going to be equal to the return value of a function call to each animal.

describe('Animal', function() {
//each animal will take in name and age as an argument
const spot = Dog('Spot', 9)
const sassy = Cat('Sassy', 7)
const hiss = Snake('Hiss', 3)
....

Next I’m going to write the first test. For the first text I want to make make sure that all the things my animals have in common are present.

...  it('All animals should eat, sleep, and bite', function () {
[spot, sassy, hiss].forEach(animal => {
animal.eat().should.equal(animal.name + ' is eating.')
animal.sleep().should.equal('..zzZZZ')
animal.bite().should.equal(animal.name + ' bit you!')
}
}
...

Here I’m just using a forEach to loop over all of my animals, call their respective common functions and then using the should assertion type from chai to check that it is equal to a certain string value.

The test-index.js file should now look like this:

//test/test-index.jsconst chai = require('chai')
const should = chai.should()
const expect = chai.expect
describe('Animal', function() {
//each animal will take in name and age as an argument
const spot = Dog('Spot', 9)
const sassy = Cat('Sassy', 7)
const hiss = Snake('Hiss', 3)
//#1st write a test for the things the animals have in common
it('All animals should eat, sleep, and bite', function () {
[spot, sassy, hiss].forEach(animal => {
animal.eat().should.equal(animal.name + ' is eating.')
animal.sleep().should.equal('..zzZZZ')
animal.bite().should.equal(animal.name + ' bit you!')
}
}
})

Now I can add in other assertions to test that animals have specific abilities:


it('cats and dogs want to cuddle', function() {
sassy.cuddle().should.equal('Sassy wants to cuddle!')
spot.cuddle().should.equal('Spot wants to cuddle!')
})
it('snakes do not cuddle', function(){
try{
hiss.cuddle()
} catch(err) {
should.exist(err)
}
})

This will make sure that we aren’t trying to just inherit all things from some parent class. I used the javascript try and catch methods to make sure that when we call hiss.cuddle() I get an error.

Let’s take that a step further and make sure I really can’t created these objects with either classical or prototypal inheritance.

it('Objects should not be an created using classical inheritance', function() {
let constString = spot.constructor.toString()
constString.substring(0,5).should.not.equal('class')
})

it('Objects should not be created using prototypal inheritance', function() {
let constString = spot.constructor.toString()
var containsThisKeyword = /this/g.test(construct)
expect(containsThisKeyword).to.equal(false)
})

Both of these tests use the constructor method to return the constructor that was used to create the object. In the first I check if the the constructor starts with the keyword class and in the second I look through the constructor to make sure the this keyword is never used. Now I should get a nice little error message if I try to cheat when building my functions.

Now in our index.js file we can start writing out our code:

const Cat = (name, age) => {
let state = {
name,
age,
species: 'Cat'
}
return Object.assign(
{},
cuddler(state),
defaultAnimal(state)
)
}
const Dog = (name, age) => {
let state = {
name,
age,
species: 'Dog'
}
return Object.assign(
{},
cuddler(state),
defaultAnimal(state)
)
}
const Snake = (name, age) => {
let state = {
name,
age,
species: 'Snake'
}
return Object.assign(
{},
defaultAnimal(state)
)
}
const cuddler = (state) => ({
cuddle: () => state.name + ' wants to cuddle!'
})
const defaultAnimal = (state) => ({
eat: () => state.name + ' is eating.',
bite: () => state.name + ' bit you!',
age: () => state.age.toString(),
name: () => state.name,
sleep: () => '..zzZZZ'
})
module.exports = {
Cat,
Dog,
Snake
}

My code at this point is already starting to look a little complicated but what’s great is that as long as all of the tests are passing I know I haven’t broken anything as I add more methods to each animal. At the bottom of the file I’ve defined with of the functions should be exported as a module to be used by other programs. So now back in our index-test.js file we should be able to import the methods like this:

const index = require('../index')
const Cat = index.Cat
const Dog = index.Dog
const Snake = index.Snake

Here I require the index.js file and set it equal to a index. Then I set all of index’s modules equal to their respective method names to avoid later confusion.

My finished index-test.js file should now look like this:

const chai = require('chai')
const should = chai.should()
const expect = chai.expect
const index = require('../index')
const Cat = index.Cat
const Dog = index.Dog
const Snake = index.Snake
describe('Animal', function() {
//each animal will take in name and age as an argument
const spot = Dog('Spot', 9)
const sassy = Cat('Sassy', 7)
const hiss = Snake('Hiss', 3)
//#1st write a test for the things the animals have in common
it('All animals should eat, sleep, and bite', function () {
[spot, sassy, hiss].forEach(animal => {
animal.eat().should.equal(animal.name + ' is eating.')
animal.sleep().should.equal('..zzZZZ')
animal.bite().should.equal(animal.name + ' bit you!')
}
}
it('cats and dogs want to cuddle', function() {
sassy.cuddle().should.equal('Sassy wants to cuddle!')
spot.cuddle().should.equal('Spot wants to cuddle!')
})
it('snakes do not cuddle', function(){
try{
hiss.cuddle()
} catch(err) {
should.exist(err)
}
})
it('Objects should not be an created using classical inheritance', function() {
let constString = spot.constructor.toString()
constString.substring(0,5).should.not.equal('class')
})

it('Objects should not be created using prototypal inheritance', function() {
let constString = spot.constructor.toString()
let containsThisKeyword = /this/g.test(construct)
expect(containsThisKeyword).to.equal(false)
})
})

Here is a link to the github repo where this demo lives: https://github.com/joshlacey/functional-programming-with-javascript. I’ll most likely be updating this in the future so if you’re reading this later things might move around a bit. The core concepts should stay the same however.

--

--

Joshua Lacey

Fullstack Webdeveloper: Javascript, Node.js, React.js, Ruby on Rails