I’m still working on the Building some NodeJS tools for machine learning and trading series and I’m ahead of it so I’ve got a few articles lined up when I have a little spare time to get them down. In the meantime though I’ve started adding testing to the code base. That’s going to be out of the scope for that series and I don’t want to spend a ton of time on it there, so I’m taking this opportunity to just briefly talk about it.

It never fails to be a point of contention whenever unit or end to end testing is brought up at my current shop. I think a lot of it just comes to down to a lack of understanding how easy it is to get started and why it’s important to have a well tested code base.

Why

We all produce well written and self documenting code right? Heh. I can’t count the number of times I thought something I produced was simple enough to read only to come back to it down the line and curse myself for not adding documentation. Then I go to modify it or call it and I get some results that I’m not expecting. So then I waste time tinkering with it to figure out why it’s doing what it’s doing and the whole time hoping any changes I’m making won’t have impacts in other areas of my application.

Having good test coverage can mitigate a lot of this. For starters tests are a form of documentation and when well written can be really descriptive. It also allows us to be confident in whatever changes we make that we’re not breaking other things. This is especially true when considering end to end tests.

For this article I’ll be talking about unit testing specifically.

Setting it up

So you’ve bought into what myself and countless others have just said and you want to get started unit testing your NodeJS code. Great! Where do you start?

There’s a lot of testing libraries and full fledged frameworks in the JavaScript ecosystem. The two most popular are probably Mocha and Jasmine.

Jasmine tries to be a complete testing framework and Mocha is a test running framework. That means if you choose mocha you’ll need to choose some other libraries for making assertions, stubs, mocks and whatever else you need in your tests. There’s no wrong answer there and in the end both have similar APIs when it comes to writing tests. Mocha will be more flexible than Jasmine but both are great choices. Since Mocha is the slightly more complicated setup I’ll go over it here.

First things first we need to install Mocha with npm or yarn.

yarn add mocha

We can go ahead and add an assertion library. The most popular one to go with Mocha is Chai, so let’s install it next.

yarn add chai

Now let’s simply create a test command. In our package.json add

scripts {

"test": "mocha"

}

You’re all setup and ready to start adding testing to your NodeJS app. It’s that simple! We can improve on this though with some simple steps. By default Mocha looks in a test folder. I prefer to have the tests in the same folder as the files I’m testing and to be prefixed with .spec.js from my ruby days. We can modify our test script to:

"test": "mocha -c \"./**/*.spec.js*\"

That will look in your root folder recursively and run tests in any files ending in .spec.js . The -c forces color in the console output. It’s easier to parse it with your eyes quickly.

Another easy upgrade to add is a test coverage report. The most popular one is instanbul and again the setup is super simple. Start with installing it:

yarn add nyc

Then once again let’s modify our test command to:

"test": "nyc mocha -c \"./**/*.spec.js*\"

Now we’ll get a brief summary in the console after our test running completes that looks something like:

Sweet. Last easy upgrade we can do is get it to output some html files if we want to view the test coverage breakdown in the browser. This can be really convenient to get information about which branches aren’t tested or lines etc… I find it easier than just the textual output in the console. So let’s modify our test command one last time to:

"test": "nyc mocha -c \"./**/*.spec.js*\" && nyc report --reporter=html"

Now after your test runner completes it’ll create a new coverage folder and inside it will build some html files. If you open the index.html in the root of that folder you’ll get a nice visual breakdown of your test coverage.

And clicking on the different links will give you a line by line breakdown of the individual test coverage per file.

That’s it now we’re ready to start writing some tests. I’ll go over some basic ideas and things I do while writing unit tests in the next section.

Writing Tests

There’s lots of discussion about how to write good unit tests. One of my personal favorites is the FIRST principles.

Fast

Isolated

Repeatable

Self-validating

Timely

Here is a link that expands on these ideas a little more. It’s a java blog but the principles remain the same in any environment.

Basically your unit tests should run quickly. They should be isolated from each other and not depend on states from previous tests. The results should be repeatable. They should determine if the output is a success or failure without the need for interpretation. It’s generally a good idea to write them as you develop.

Let’s write out some examples. Since we already set it up to run any file in our code base ending with .spec.js we can just create these anywhere. If we had a file in our code base called main.js in the root directory with some code exported from it like:

We can create a new file in the same directory called main.spec.js . Inside we’ll start with requiring our dependencies and then just write a few tests for it.

This is some simple tests for the add function we created in our main.js . The mocha test runner injects a describe() function and an it() function into the global namespace. They both take a string as an input for the first parameter and a function to write out test in as the second parameter. If we run npm test now, we’ll get an output that looks like:

Sweet, right? We can also take a look at the output from our coverage files that should have been generated.

You can follow the same kind of formula and add tests for the other functions. I’ll leave that exercise for you, it’s good for understanding to write out the code yourself.

That’s all it takes to get started. It can be pretty satisfying to watch your coverage numbers slowly increase with ever run of the testing base until you hit the magic across the board 100%s. It’ll help you remain confident in your code base and even though writing the tests and becoming an efficient test writer does take time, it’s an investment. The time spent on it now will pay off in times savings in the future.

A quick note on stubs and mocks

In order to keep your tests isolated from each other and to make sure you’re testing the small units of code, generally just a function or method at a time, you’re going to quickly find it useful to start using stubs and mocks.

Stubs and mocks are a way to fake responses from calls within the unit of code you’re testing. So for example if you have a call inside a function you’re testing that gets data from an external API, your test will fail if something external to it (the API in this case) fails. That doesn’t meet our FIRST principles. It won’t be fast and it won’t be repeatable. We can stub this call instead. In this case we would intercept this call with a fake function we create and return “canned” data. This will make it faster and repeatable. It also has the benefit of testing only what we want to test which is our function and not the current state of an external API.

A library I find that goes well with Mocha and Chai is Sinon. There’s also a middleware Sinon-chai that adds some assertions to the chai library. They’re mostly just for convenience but it allows us to write things that are more Chai-esque when using stubs or mocks. Instead of:

mySpy.calledWith("foo").should.be.ok;

expect(mySpy.calledWith("foo")).to.be.ok;

You can write:

mySpy.should.have.been.calledWith("foo");

expect(mySpy).to.have.been.calledWith("foo")

Thanks for reading. If this helps you drop a clap and follow. Leave some comments especially if you have suggestions or questions. Don’t be afraid of unit testing, embrace it, you’ll be happy you did in the long run.