Helpful Node.js testing utilities
This is not a post about Node.js' testing frameworks, assertion libraries or mocking libraries like Jest, Chai, Mocha and Sinon. This is a short list of libraries that provide functionality that has helped me set up an effective test environment.
Decache
This is my number 1 tool when testing a library I'm building that stores global state. Here's what their readme says:
In node.js when you require() a module, node stores a cached version of the module, so that all subsequent calls to require() do not have to reload the module from the filesystem. decache ( Delete Cache ) lets you delete modules from node.js require() cache
I used decache in my event management library, Burns. I use it to restore the state of the module being tested in an afterEach
hook. This is especially important as Burns keeps track of global state.
Mitm
Mitm is a package for intercepting network calls (TCP or HTTP) dispatched from your code. I 've used mitm to fake responses from the Twitter API in my Twitter reminders bot, @RemindMe_OfThis. It allows me to basically do whatever I like, such as recording the requests and responding differently depending on the request data.
mock-require
mock-require allows you override require
calls by specifying what should be returned when a particular module is returned. [I used it multiple times in @RemindMe_OfThis] (https://github.com/shalvah/RemindMeOfThisTweet/blob/master/spec/support/mocks.js) to return my own fakes for dependencies my code needed.
Now, some folks would probably say I should have used dependency injection instead, in which case I could easily inject my mocks without having to use mock-require
or hack Node.js' module system. They're probably right. However, in my experience, it's been quite painful (and overkill) implementing DI in Node.js (especially when there's no static typing). I prefer to stick with the straightforward approach—the module system.😀
Some alternatives to mock-require:
rewire
: This does a similar job, and more, but you have to replace yourrequire
call withrewire
and then manually specify the mocks. One advantage of that is that you're only mocking for that instance, not globally. This didn't fit my use case, though.proxyquire
: Similar torewire
, it replacesrequire()
and lets you override on a per-instance basis, but with a simpler API.
MockDate
This is a very specific utility, one that will only come in handy if you're working with dates/times and need to have control over the time exposed to your code. It's quite simple to use—you just need to call require('mockdate').set(date)
and whenever you call new Date()
, you'll get that date. One important caveat is that you can't change the timezone, though—Node.js doesn't let you do that easily (until version 13).
redis-mock
This is an even more specific package—it's a mock of node-redis
. The idea is to give you a fake datastore so that your code continues to think it's talking to a live Redis server, but it's really talking to an in-memory object managed by redis-mock
.
I used it (in combination with mock-require) in my Twitter video downloader bot, @this_vid to fake the bot's datastore. The cache can be easily reset for each test by flushing it like you would a real cache in a (beforeEach
/afterEach
hook)
I love most of these tools because of how "drop-in" they are, allowing me to "pretend" to use the actual objects . Many of them may not conform to some strict ideas about testing and mocking, but I like them because they're simple and allow me to focus on testing my application logic rather than setting up some unnecessarily complicated architecture.
I write about my software engineering learnings and experiments. Stay updated with Tentacle: tntcl.app/blog.shalvah.me.