This blog post serves as a practical introduction to testing your Node.js code. If you're wondering why you should spend your valuable development time writing tests, read this and this. In short, tests save you from avoidable bugs that take up many frustrating hours to find and fix. They also give you the confidence to refactor and improve your existing code without fear of breaking existing functionality.
Java protects us from ourselves - it doesn't allow a or b to be anything other than ints and it does not allow us to return anything other than an int.
Node development is modular. We have a number of tools tackling problems with testing. I've listed my favorite stack here:
In classic Node style, we don't have one end-all-be-all solution for testing - instead we have a number of libraries that each tackle one specific problem.
We use Mocha to set up and run our tests.
Notice that we needed a second library just to run the tests - Mocha doesn't provide assertions. This is where Chai comes in. Chai lets us write assertions in a human, readable way. Its API gives us the power to write comprehensive tests.
- A way to make sure they're used correctly.
- A way to stub their output.
Sinon provides this functionality.
Great! Now we can write tests not just for our pure functions, but also for modules that have internal dependencies.
But what if we have external dependencies? We can't simply set our Sinon stub/spy to the functions on our require'd modules, since that require is opaque to anything outside of our module. This is where our final library, Mockery, comes into play. Mockery can stub require and return whatever we want instead of the original dependency.
Using these four tools, we can create a complete test for most applications.
Write Testable Code
The gurus at Google have written an excellent guide to writing testable code. Three qualities I suggest you strive for in your code are:
- Design small, single purpose units of code
- Limit reliance on state (write pure functions)
- Don't make undocumented assumptions about your input and output
Writing tests is vital for stable, long-lived applications. With Node.js and NPM, we have access to powerful tools that help us create comprehensive, useful tests. But in order to test effectively, we must first write code that is conducive to testing.