Skip to content
SDETRole
SDETRole

Glossary · Testing fundamentals

Test double

Also called: test doubles, test stub, test stubs, mock object

Definition

Any object that stands in for a real dependency in a test, such as a dummy, stub, fake, spy or mock, so the code under test runs fast and predictably.

A test double replaces a real dependency, such as a payment gateway, database, clock or email service, with something the test controls. The name, popularized by Gerard Meszaros, comes from the stunt double in films. Doubles make tests fast and deterministic, and let you simulate situations that are hard to produce for real, like a timeout or a declined card.

The five kinds

Type What it does Example
Dummy Passed only to fill a parameter, never used A null or empty logger the method requires but this test never touches
Stub Returns canned answers to calls rates.getRate("EUR") always returns 0.92
Spy A stub that also records how it was called Records that send() was called once with a given address
Mock Pre-programmed with expectations, and the test verifies the interactions Verify gateway.charge(4999) was called exactly once
Fake A working but simplified implementation An in-memory repository backed by a HashMap

In everyday speech “mock” is used for all of these, and libraries like Mockito create objects that can act as stubs, spies or mocks. Knowing the distinction still helps, especially stub vs mock: a stub supplies inputs to the code under test (state verification), while a mock checks the outputs the code sends to its dependencies (behavior verification).

Example (JUnit 5 with Mockito)

@Test
void declinedCardDoesNotSendConfirmation() {
    PaymentGateway gateway = mock(PaymentGateway.class);
    EmailService email = mock(EmailService.class);
    when(gateway.charge(4999)).thenReturn(PaymentResult.DECLINED); // stub

    var checkout = new Checkout(gateway, email);
    var result = checkout.placeOrder(4999);

    assertEquals(OrderStatus.PAYMENT_FAILED, result.status());
    verify(email, never()).sendConfirmation(any()); // mock-style verification
}

(Static imports from org.mockito.Mockito, org.mockito.ArgumentMatchers and org.junit.jupiter.api.Assertions are omitted.)

Common mistakes

  • Mocking everything. Tests that verify every internal call break on every refactor and can pass while the real integration is broken. Mock at architectural boundaries; prefer real objects or fakes inside them.
  • Doubles that drift from reality. A stubbed API that returns a field the real service renamed months ago gives false confidence. Contract tests and a few real integration tests keep doubles honest.
  • Mocking types you do not own. Wrap third-party clients in your own interface and double that instead.

Type to search across SDETRole.

Full-text search by Pagefind · runs in your browser Open search page →