Image for post
Image for post
Photo by Becky Phan on Unsplash

Understanding Jest Mocks

Rick Hanlon II
Mar 8, 2018 · 4 min read

Mocking is a technique to isolate test subjects by replacing dependencies with objects that you can control and inspect. A dependency can be anything your subject depends on, but it is typically a module that the subject imports.

For JavaScript, there are great mocking libraries available like testdouble and sinon, and Jest provides mocking out of the box.

Recently, I joined Jest as a collaborator to help triage the issue tracker, and I’ve noticed a lot of questions about how mocking in Jest works, so I thought I would put together a guide explaining it.

When we talk about mocking in Jest, we’re typically talking about replacing dependencies with the Mock Function. In this article we’ll review the Mock Function, and then dive into the different ways you can replace dependencies with it.

The Mock Function

The Mock Function provides features to:

  • Capture calls
  • Set return values
  • Change the implementation

The simplest way to create a Mock Function instance is with jest.fn().

With this and Jest Expect, it’s easy to test the captured calls:

and we can change the return value, implementation, or promise resolution:

Now that we covered what the Mock Function is, and what you can do with it, let’s go into ways to use it.

Dependency Injection

This strategy is solid, but it requires that your code supports dependency injection. Often that is not the case, so we will need tools to mock existing modules and functions instead.

Mocking Modules and Functions

  • jest.fn: Mock a function
  • jest.mock: Mock a module
  • jest.spyOn: Spy or mock a function

Each of these will, in some way, create the Mock Function. To explain how each of these does that, consider this project structure:

In this setup, it is common to test app.js and want to either not call the actual math.js functions, or spy them to make sure they’re called as expected. This example is trite, but imagine that math.js is a complex computation or requires some IO you want to avoid making:

Mock a function with jest.fn

This type of mocking is less common for a couple reasons:

  • jest.mock does this automatically for all functions in a module
  • jest.spyOn does the same thing but allows restoring the original function

Mock a module with jest.mock

From here, we can use any of the above features of the Mock Function for all of the exports of the module:

This is the easiest and most common form of mocking (and is the type of mocking Jest does for you with automock: true).

The only disadvantage of this strategy is that it’s difficult to access the original implementation of the module. For those use cases, you can use spyOn.

Spy or mock a function with jest.spyOn

In these cases, you can use jest.spyOn.

Here we simply “spy” calls to the math function, but leave the original implementation in place:

This is useful in a number of scenarios where you want to assert that certain side-effects happen without actually replacing them.

In other cases, you may want to mock a function, but then restore the original implementation:

This is useful for tests within the same file, but unnecessary to do in an afterAll hook since each test file in Jest is sandboxed.

The key thing to remember about jest.spyOn is that it is just sugar for the basic jest.fn() usage. We can achieve the same goal by storing the original implementation, setting the mock implementation to to original, and re-assigning the original later:

In fact, this is exactly how jest.spyOn is implemented.

Conclusion

I hope this helped to simplify your understanding of Jest mocks so you can spend more time writing tests painlessly. For more info and best practices for mocking, check out this this 700+ 😱 slide talk titled Don’t Mock Me by Justin Searls .

Hit me up on twitter, Stack Overflow, or our Discord channel for any questions!

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store