unmock vs nock - comparing two JS mocking frameworks
8th Feb 2020
When we built
unmock, we took a lot of inspiration from
nock, and we often get asked what the difference is between the two libraries. Here's a brief explanation with some examples.
Mocking is used mostly in tests when the code you want to test relies on a REST API call, like a call to a third-party service or an internal microservice. A mock is a stand-in for software, like a service or database or library, that captures a small portion of the original's functionality while being simpler to maintain and access than its real counterpart. When testing code involving a REET API, it's usually a good idea to mock the API in order to avoid making a network call from your tests. There are four main advantages of mocking instead of making a network call.
- If the network is down, your tests can still run.
- Network calls are slow.
- In general, you don't want to access production data or shared resources, like staging environments, during tests.
- Writing mocks allow you to specify corner cases you'd like to test.
You can install both
nock using NPM or yarn.
If you are a typescript user, you will need to install the
nock types separately.
unmock is written in typescript, so no additional installation is needed.
Here's how you mock an endpoint with fixed data in both
nock. By "fixed data", I mean data that is entirely deterministic and doesn't change from test to test. The two examples below use
nock have almost no differences when using fixed mocks.
Truth be told, I'm not a fan of fixed mocks. In my opinion, the issue with using them is that they hardcode assumptions about mock data in the test. For example, the test above knows that the mock data contains five elements and that the order of minors will be
[false, true, false, false, true]. Does that mean we expect that the function will always return five elements? That the order of minors will always be the one above? We have no way to know the answers to these questions from looking at the tests alone, and its easy for newcomers to confuse characteristics of a mock with expectations about how the function will behave (ie thinking "Oh, this function always returns five users.", etc).
One solution to this problem is to use dynamic mocks.
Let's rewrite the example above in
unmock to use dynamic mocks. Dynamic mocking is not possible in
Not only is the test shorter - it conveys our intent with greater clarity. We expect that, for every user in the list, they will be flagged as minor if their age is less than 18. Furthermore, we expect our API to return an array of user objects with a
string name and
integer age. For more on the
u. sytanx in
unmock, check out the documentation.
While dynamic mocks are useful, they are limited to a single test case. What if the code has a bug when there are zero users? 100 users? Users in various orders of age? Dynamic mocks take us half way there - to cross the bridge fully, we need fuzz testing.
unmock is most powerful when used with the
runner. Let's use the same test above, adding the
runner right after the string defining the test.
The only change in the code above from the previous example is that we have added the runner in the test definition. This runs the test twenty times by default, although the number of times is tweakable. The advantage of this approach is that the runner will throw lots of different permutations of data at your function (empty array, large array, different orders of elements), which is a great way to expose bugs. It's also a more realistic way to test APIs - as you never know what an API will return, testing with a runner is a good way to increase confidence that your code will handle a wide range of outcomes.
You can check out the
runner documentation for more information. We are currently actively developing the runner to better explore common corner cases and to support more test frameworks, like
unmock may be a good fit. In addition to these features,
unmock contains spies that provide information about data coming into and going out of the REST APIs you consume. It also has a functional API for tweaking responses in case you need to narrow the range of possible outcomes produced by the runner.
We hope you enjoy checking out
nock and one or both of them useful in your next JS or TS project that makes REST API calls!