Mock

Tool

A stand-in object you drop into a test in place of the real component, built to return fixed answers instead of doing the real work.

Why it exists

A test is a machine checking that code behaves the way it was meant to. If the code under test only calculates something, you feed it a value and look at the result. Real code usually leans on something outside itself: payment code calls a card processor, notification code calls a mail server, a list screen pulls rows out of a database.

Leave those connections in place and three problems arrive together. Each test takes seconds instead of milliseconds. Real requests go out to somebody else's service, which costs money or triggers an actual charge. And when that service is down for maintenance, your test fails even though your code is fine.

Friday afternoon is when this shows up. The automated check that runs on every merge goes red, Theo spends half an hour looking for the cause, and the answer is that his change was fine and the card processor's test server was under maintenance. If it happens again on Monday, the team switches the test off.

A mock cuts that connection. Put a fake that always answers "approved" where the real processor was, and the test goes back to checking your code rather than someone else's uptime.

What it solves

It removes the test's dependence on things you don't control. Four of those in particular.

  1. Speed — if one real call takes two seconds, the 300 tests that touch it take ten minutes. Answers from a mock come out of memory, which brings the whole suite down to seconds, and only then will a developer run it after every change.
  2. Cost and side effects — a payment test must not authorize real money every time it runs. Mail is the same. Testing notification code a hundred times shouldn't put a hundred messages in a customer's inbox.
  3. Stability — when someone else's slow server turns your check red, the team learns to shrug and re-run it. That's a flaky test, a test that passes and fails on identical code, and as those pile up the suite stops working as a warning. A red light nobody believes is worse than no light.
  4. Hard-to-reproduce conditions — a declined card over its limit, a response that never arrives, an outage on the processor's side. These are close to impossible to stage for real, and a mock can return exactly those answers, which makes it the only practical way to test what your code does when things go badly.

There's one more thing a mock does. It doesn't just answer, it remembers how it was called. Whether a double-clicked pay button sent one request or two isn't visible in the return value; you find it out by asking the mock how many times it was called.

Alternatives

A mock isn't always the right cut, and four other approaches address the same problem. Which one fits depends on whether you're trying to remove slowness or remove side effects.

  1. Sandbox — send real requests to the test environment the other company provides. A test card number moves no real money but returns a real response. It's slow, but the shape of what comes back matches production, so tests that verify the integration itself belong here.
  2. Fake implementation — instead of imitating, build a small thing that genuinely works, like an in-memory store standing in for a database. It costs more to write than a mock and gets reused across many tests.
  3. Fixture — the state and data laid down before a test runs. If the awkward part is setup rather than an outside connection, this is the tool, not a mock.
  4. Record and replay — capture a real response once, save it to a file, and serve that file afterwards. Closer to reality than a mock, but the saved file quietly goes stale when the other side changes its response format.

The rule of thumb is short. Use mocks in a unit test, where one piece of code is pulled out and examined alone, and use something closer to the real thing where the point is whether the assembled parts actually fit. Keep only one of the two and you end up with a suite that is fast but unconvincing, or trustworthy but never run.

How it sounds at work

"Can you switch this test to a mock processor? Their maintenance window is turning our checks red."

Nothing is wrong with our code, so cut the outside connection.

"Over-the-limit is something only a mock can produce. Reproducing it for real means maxing out a card."

The condition can't be staged, so it gets faked to be tested at all.

"There are so many mocks in this test that I can't tell what it's actually verifying."

So much of the surrounding code was replaced that the remaining assertion lost its meaning.

When Pagedeck added payments for paid conversion, the first thing Theo built was a fake processor. It returned four answers — approved, over the limit, expired card, and no response after ten seconds — and he checked what the screen did for each. A real card could only produce the first one; there was no way to stage the other three.

The bill came six months later. The processor changed the format of its decline response, the mock kept returning the old format, and the checks stayed green while the failure screen broke in production. Nobody noticed until a customer wrote in to say the app showed a blank page after a declined card. Pagedeck now runs a second suite once a day that sends real requests to the sandbox, separate from the mocked ones, and that suite exists specifically to catch the day the other side changes something.

What people get wrong

It's easy to assume more mocks make a suite better. Tests get faster and stop breaking, which looks like progress on every visible measure. But a mock is your understanding of the other side written down, so when that understanding is wrong or has aged, the suite goes green on a false premise. That's exactly what happened to Theo. As mocks multiply, the test coverage number climbs while the amount actually verified drops.

Replacing everything around the code under test is the other common misstep. It comes from wanting to isolate the cause precisely, but past a point the test stops checking behavior and starts checking the order in which your code calls things. Refactor the implementation without changing what it does and the test breaks anyway; after that happens a few times, the team edits tests every time it edits code. Mocks belong only where something is genuinely outside your control.

Easily confused with

TermWhat it isHow it differs
FixtureThe state and data laid down before a test runsA fixture is a prop placed on the stage; a mock is the stand-in who answers lines. A fixture creates "three documents already exist," while a mock handles "when a payment request arrives, say approved"

Where to go next

  • Testing

    see the activity this tool belongs to

  • Fixture

    the tool used alongside it in the same setup step

Last updated 2026-09-16