Mock Functions in React Testing

Mock functions replace or observe dependencies so tests can verify calls, arguments, and controlled return values. In Jest, `jest.fn()` creates a mock function whose calls and behavior can be inspected during a test.

A mock function is a test double that stands in for a real function. In frontend tests, this is useful when a component depends on callbacks, API wrappers, or other functions whose real behavior is unnecessary or undesirable during the test.

Jest provides `jest.fn()` to create mock functions. The returned function records information such as how many times it was called and which arguments it received. This lets a test verify interactions without executing the original implementation.

You can also control what a mock returns. Methods such as `mockReturnValue()` provide a fixed result, while `mockImplementation()` supplies custom behavior. For asynchronous code, `mockResolvedValue()` and `mockRejectedValue()` are convenient for simulating fulfilled or rejected promises.

Mocks should generally be configured around the behavior being tested rather than used everywhere. Over-mocking can make a test pass even when the real integration between pieces is broken. A good test uses mocks to isolate a dependency while still checking meaningful behavior.

Key points

Interview questions

What is a mock function, and why would you use one in a React test?

A mock function is a controllable replacement for a real function used by the code under test. In React tests, it is commonly used for callback props or dependencies whose real implementation is not relevant to the test. Jest's `jest.fn()` also records calls, so the test can verify that an interaction occurred. This helps isolate the component and make the test deterministic.

How do you verify that a mock function was called with a particular argument?

Create the function with `jest.fn()`, invoke the code being tested, and use `toHaveBeenCalledWith()` with the expected argument. You can also use `toHaveBeenCalledTimes()` when the number of calls matters. Jest compares the supplied arguments against the mock's recorded call history.

How can you control what a mock function returns?

For a fixed synchronous value, use `mockReturnValue()`. If the behavior needs logic, use `mockImplementation()`. For promise-based dependencies, `mockResolvedValue()` and `mockRejectedValue()` make it easy to simulate success and failure paths. This allows a test to exercise different states without relying on the real dependency.

What is the difference between clearing and resetting a Jest mock?

Clearing a mock removes its recorded call information while keeping its configured implementation. Resetting goes further by removing the mock's recorded state and its configured behavior. The distinction matters when a mock is reused across tests. Tests should deliberately choose whether they need to preserve the configured implementation.

What are the risks of overusing mocks in frontend tests?

Heavy mocking can produce tests that verify an artificial implementation rather than the application's real behavior. For example, mocking too many internal modules can hide integration problems between components and dependencies. Tests should mock boundaries that are expensive, nondeterministic, external, or irrelevant to the behavior under test. Keeping more realistic interactions where practical can provide stronger confidence.