stackademic

The leading education platform for anyone with an interest in software development.

Mocking

Replacing real dependencies with controllable stand-ins during a test

Overview

A mock is a fake version of a dependency that you control inside a test. Mocks let you test a unit without calling a slow or unpredictable dependency like a network request, a clock, or a payment API. They also let you assert how your code used a dependency, such as which arguments it passed.

Syntax / Usage

Jest can replace a function with jest.fn() and let you program its return value. You then assert both the result and how the mock was called.

// notify.js
async function notify(emailClient, user) {
  if (!user.email) return false;
  await emailClient.send(user.email, "Welcome!");
  return true;
}
module.exports = { notify };

// notify.test.js
const { notify } = require("./notify");

test("sends a welcome email to the user", async () => {
  const emailClient = { send: jest.fn().mockResolvedValue(undefined) };
  const user = { email: "ada@example.com" };

  const result = await notify(emailClient, user);

  expect(result).toBe(true);
  expect(emailClient.send).toHaveBeenCalledWith("ada@example.com", "Welcome!");
  expect(emailClient.send).toHaveBeenCalledTimes(1);
});

Examples

Skipping work when a precondition fails, verified by an unused mock:

test("does not send when email is missing", async () => {
  const emailClient = { send: jest.fn() };
  const result = await notify(emailClient, { email: null });

  expect(result).toBe(false);
  expect(emailClient.send).not.toHaveBeenCalled();
});

Controlling time so a date-based function is deterministic:

test("uses a fixed current date", () => {
  jest.useFakeTimers().setSystemTime(new Date("2026-01-01"));
  expect(new Date().getFullYear()).toBe(2026);
  jest.useRealTimers();
});

Common Mistakes

  • Mocking so much that the test no longer verifies real behavior
  • Forgetting to reset mocks between tests, leaking call counts across cases
  • Asserting a mock was called but never checking the arguments
  • Mocking code you own instead of just its external dependencies
  • Letting the mock's return shape drift from the real dependency's shape

See Also

testing-unit-tests testing-integration-tests testing-test-driven-development