Written by Jeremy Kithome✏️
Introduction
If you are reading this article, you probably know what Node.js is. Node.js is often used in creating APIs. It has steadily grown in popularity since its initial release in 2009.
According to SimilarTech there are over 85000 unique domains using Node.js today. Stackshare lists Uber, Twitter, Netflix, Medium, Slack, Reddit, and eBay as companies using Node.js.
In this post, we will be looking at unit testing in Node.js. For those of you who don’t know, unit testing is a software testing method where individual pieces of code (usually the smallest piece of code that can be logically isolated in a system) are tested in isolation. Unit tests should be isolated such that there are no external dependencies. Let’s look at some advantages and disadvantages of unit testing.
Advantages of unit testing:
- It makes it easier to identify bugs in code earlier. Appropriate test cases should be written for every piece of code to ensure that it meets specifications and provides the desired output. Any changes that result in failing tests will indicate that an error or bug has been introduced. Additionally, unit testing makes it easier to narrow down the offending piece of code
- Unit tests act as self-documentation. A new team member can gain a better understanding of the codebase by going through unit tests
- The debugging process is made a lot easier. This is because when the test fails, the focus will be on the latest changes made
- Refactoring code is made easier since changes can be verified using tests to ensure that the unit being tested still behaves in the desired manner
- Costs that would be incurred fixing bugs or due to system outages occasioned by bugs are reduced
Testing frameworks provide a set of reusable components or modules such as test runners and utilities for running automated tests. The testing framework is responsible for:
- Describing the format used to convey test expectations
- Creating a way of accessing the application or code to be tested
- Executing the tests
- Reporting test results
They are particularly useful when tests are an integral part of your continuous integration process. Frameworks are built for a specific type of testing; unit, integration, functional or combinations of these.
What makes a good testing framework?
Testing frameworks are a dime a dozen. In order to pick something that works for your use case, you need to evaluate each framework based on your needs and characteristics. Below are a few points that are essential for a good testing framework:
- Ease of setup – getting up and running with your tests should take a minimal amount of effort
- Well supported – there is plenty of excellent documentation and communities to get help
- A wide array of feature sets – the framework has things such as matchers, spies, mocking in-built
- Speed – for tests that are CPU bound, choosing the right framework can save you a lot of time during test runs
- Ease of reporting – coverage reports should be easy to generate using in-built reporting or external reporting libraries should be easy to intergrate
- A good testing library should be easy to integrate into your continuous integration process
Comparison of unit testing frameworks
According to the State of JS 2018 survey, the most popular JavaScript testing frameworks and libraries are:
In this post, we will compare some of the most popular and widely used frameworks; Jasmine, Jest, AVA, and Karma.
Jest
Jest is a JavaScript testing framework developed and maintained regularly by FACEBOOK. It rose in popularity in 2017. In 2016, only 6% of people surveyed for the State of JS had used Jest before as opposed to 25% in the 2017 survey. It is based on Jasmine but has been greatly improved since the early days.
Pros
- Jest is well documented. The Jest documentation has a lot of detailed instructions on how to set up testing, writing different types of tests, utilizing its many features as well as great examples.
- Easy to set up – flexible and easy configuration and less boilerplate code than other frameworks
- Parallel test running
- Fast – tests are parallelized by running them in their own processes to maximize performance
- It includes features like snapshots, coverage, and test watching
Cons
- Jest displays multiple error messages for the same error
- It can require more dependencies during initial setup (e.g babel)
Sample Jest test:
describe("Sum numbers", () => {
test("it should sum two numbers correctly", () => {
const sum = 1 + 2;
const expectedResult = 3;
expect(sum).toEqual(expectedResult);
})
});
Jasmine
Jasmine, on the other hand, has been around for a lot longer. It was developed by Pivotal Labs and released in 2010. It aims to run on any JavaScript-enabled platform and is highly flexible and compatible with a variety of other testing frameworks and libraries like Sinon and Chai. Additionally, due to its longevity, it has developed a significant community and support around it with lots of libraries, blog articles, and tutorials.
Pros
- Simple to setup. Jasmine has a CLI tool that creates a spec folder and a JSON configuration file. With one command you are ready to start testing your code
- It has been around for a long time and is thoroughly tested, documented, and there are a lot of tutorials on how to use it
- It is behavior-driven development focused with descriptive syntax
- It’s supported by many CI servers with plugins available for some of those that don’t have out of the box support
Cons
- Unfriendly error logs
- Asynchronous testing can be quite a hustle. Testing asynchronous code often requires more code and tweaks than other testing frameworks with inbuilt promise support
- Test files must have a specific suffix (*spec.js)
- In the past, there have been complaints about the maintenance team not being very responsive to pull requests or issues. A look at their open pull requests shows that this is improving however
- The assertion library is not as rich as Chai
Sample Jasmine test:
describe("Sum numbers", function() {
it("should sum two numbers correctly", function() {
var sum = 1 + 2;
var expectedResult = 3;
expect(sum).toEqual(expectedResult);
});
});
AVA
Minimalism is the focus of AVA. It has a simple API while still supporting advanced features. It is quite fast and achieves this by running tests in parallel as separate Node.js processes. Unlike other testing frameworks such as Jest and Jasmine, it does not create test globals.
Pros
- It’s simple and easy to use. To install and setup AVA, all you have to do is run
npm init ava
- Parallel test running
- Native ES6/ES7 support
- It has built-in support for async functions
- If a promise is returned, you don’t need to end the test yourself. It will end when the promise resolves
Cons
- AVA is relatively new. The community is still growing and there isn’t a lot of documentation or tutorials like other testing frameworks
- AVA has a lot of open issues at the moment
Sample Ava test:
import test from 'ava';
test('Sum numbers', t => {
const sum = 1 + 2;
const expectedResult = 3;
t.equal(sum, expectedResult);
});
Mocha
Mocha, like Jasmine, has been in existence for quite a while. It was initially released in November 2011. However, unlike other frameworks like Jest and Jasmine, it relies on third-party assertions, mocking, and spying tools(Spies are objects that keep track of their interaction with other objects or pieces of code. They keep a record of things such as the number of calls, arguments passed to specific functions and return values which can be used to make assertions.) e.g Sinon and Chai. It is very extensible and has a lot of plugins, extensions, and libraries designed to run on top of it.
Pros
- Highly extensible and therefore has support for different assertion and mocking libraries
- Easy asynchronous testing
- Adding support for generators to test suites is relatively easy. Using the co-mocha package, all you have to do is require it in your tests and you are ready to use generators
- Supported by some CI servers and plugins for others
Cons
- The use of extra libraries can introduce configuration complexity and also increases maintenance work
- No auto mocking available
Sample Mocha test:
const { expect } = require('chai');
describe('Sum numbers', () => {
it('should add two numbers correctly', () => {
const sum = 1 + 2;
const expectedResult = 3;
expect(sum).to.equal(expectedResult);
});
});
The table below shows a comparison of the features across the different frameworks:
Framework | Jasmine | Ava | Jest | Mocha |
---|---|---|---|---|
Open source | YES | YES | YES | YES |
In-built coverage reporting | NO | NO | YES | NO |
Parallel test running | NO | YES | YES | NO |
Snapshots | NO | YES | YES | NO |
In-built spies | YES | NO | YES | NO |
In-built mocking | YES | NO | YES | NO |
In-built assertions | YES | YES | YES | NO |
ES2017 support | NO | YES | YES | NO |
Choosing the best framework
The best framework can vary based on your needs, project size, and other factors. What works now might not work in the future. It is important to take both your current and future needs into consideration when choosing the right framework.
If you want to hit the ground running, you cannot go wrong with Jest. It is an extremely fast framework, easy to set up and has a lot of built-in features to help you with your testing.
When it comes to simplicity, AVA is your cup of tea. It is minimal, simple, but capable of handling various types of test. It is also fairly fast.
Mocha is the best choice for someone that wants flexible configurations as well as a choice of libraries to use together with it.
Conclusion
There are very many frameworks and libraries that you can use to test your Node.js projects. In this article, we have focused on four of the most popular frameworks. Remember, your choice of testing framework will depend on your needs. In some cases, some libraries will be deficient and in others, they will be overkill.
Editor's note: Seeing something wrong with this post? You can find the correct version here.
Plug: LogRocket, a DVR for web apps
LogRocket is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.
In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.
Try it for free.
The post The best unit testing frameworks for Node.js appeared first on LogRocket Blog.
Top comments (1)
No Tape.js?