Interview answer drill

Use this JavaScript interview question to rehearse a quick answer, common mistake, follow-up, and production pitfall.

Mocks vs Stubs vs Spies (Test Doubles) in JavaScriptFrontend interview answer

HighIntermediateJavascript
Interview focus

This JavaScript interview question tests whether you can explain Mocks vs stubs vs spies: what is the difference, connect it to production trade-offs, and handle common follow-up questions.

  • Mocks vs stubs vs spies: what is the difference explanation without falling back to memorized docs wording
  • Testing and Best Practices reasoning, edge cases, and production failure modes
  • How you would answer the most likely JavaScript interview follow-up
Practice more JavaScript interview questions
Interview quick answer

Explain the difference between mocks, stubs, and spies in unit testing. Describe when to use each, how to avoid brittle tests, and how dependency injection helps testability. Include an async example and common pitfalls.

Full interview answer

Why this matters

In interviews and real code, testing isn't about writing 200 assertions—it’s about verifying behavior at the right boundary. Test doubles (mocks/stubs/spies) let you isolate a unit from slow, flaky, or external dependencies (network, storage, time, analytics).

Practical scenario

You have searchUsers(query) that calls an HTTP client and returns parsed JSON. In a unit test, you don’t want real network. You want to:

  • Stub the HTTP client to return a controlled response.
  • Spy on the client to assert it was called correctly.
  • Optionally mock the client to both define expectations and fail if they’re not met.

Test double

What it is

Use it when

Common smell

Spy

Records calls (args/call count)

You want to verify interactions at a boundary

Asserting exact call order everywhere

Stub

Returns fake data to drive a code path

You need deterministic input (no real network/time)

Stubbing internal implementation details

Mock

A stub + expectations ("must be called with X")

You want strict interaction contracts for critical boundaries

Over-mocking makes refactors painful

Rule of thumb: prefer stubs for inputs, spies for boundary verification, mocks only when strict contracts are worth the brittleness.
JAVASCRIPT
// Dependency injection makes testing simple.
// Production code:
export async function searchUsers(query, { fetchJson }) {
  if (!query) return [];
  const data = await fetchJson(`/api/users?q=${encodeURIComponent(query)}`);
  return Array.isArray(data) ? data : [];
}

// Unit test idea:
const calls = [];
const fetchJsonStub = async (url) => {
  calls.push(url);
  return [{ id: 1, name: 'Ada' }];
};

const users = await searchUsers('a', { fetchJson: fetchJsonStub });
// Assert output (preferred)
expect(users).toEqual([{ id: 1, name: 'Ada' }]);
// Assert boundary interaction (spy-like)
expect(calls).toEqual(['/api/users?q=a']);
                  

Common pitfalls

  • Over-mocking: tests fail on harmless refactors because they assert internal steps, not outcomes.
  • Leaking globals: stubbing global.fetch or Date.now without restoring breaks other tests.
  • Async flakiness: tests that depend on real timers or network ordering become flaky.
  • Missing error paths: only testing the happy path hides retries/timeouts/empty responses bugs.

Trade-off to mention in interviews

Unit tests are fast and isolate logic but can drift from reality if you mock too much. Integration tests catch wiring issues but are slower and harder to debug. A strong strategy uses both:

  • Unit tests for core logic + edge cases.
  • A few integration tests for the most important flows (auth, payments, critical UI paths).

Answer to land

"I prefer dependency injection so I can stub inputs and spy on boundaries. I assert outputs first, then interactions only when they’re part of the contract (e.g., a retry policy or analytics call). Mocks are useful for strict contracts, but I avoid over-mocking because it makes tests brittle."

Similar questions
Guides
Preparing for interviews?

Use this as one explanation rep, then continue with the JavaScript interview questions cluster or a guided prep path.