Stage 7: Tools and testing, lesson 4 of 7

Mocking with Mockito

Intermediate3 min readall versions
Explain it forThe essentials plus production detail and pitfalls.

Unit tests shouldn't call real databases, payment gateways or email servers. Mockito creates stand-ins for dependencies:

  • mock(PaymentGateway.class), or @Mock with @ExtendWith(MockitoExtension.class)
  • Stub behaviour: when(gateway.charge(anyLong(), anyString())).thenReturn("pay_1")
  • Simulate failures: thenThrow(new GatewayException("declined"))
  • Verify interactions: verify(receipts).send(order, "pay_1") and verify(receipts, never()).send(any(), any())
  • Capture arguments with ArgumentCaptor

Mock what is slow, external or not yours; don't mock simple value objects or the class you're testing. Constructor injection makes this easy, because you pass the mocks into the constructor.

Example

Java
@ExtendWith(MockitoExtension.class)
class CheckoutServiceTest {

    @Mock PaymentGateway gateway;
    @Mock ReceiptSender receipts;
    @InjectMocks CheckoutService checkout;

    @Test
    void chargesAndSendsReceipt() {
        Order order = new Order("ORD-1", 149900);
        when(gateway.charge(149900, "ORD-1")).thenReturn("pay_42");

        checkout.checkout(order);

        verify(receipts).send(order, "pay_42");
    }

    @Test
    void doesNotSendReceiptWhenPaymentFails() {
        Order order = new Order("ORD-2", 99900);
        when(gateway.charge(anyLong(), anyString())).thenThrow(new GatewayException("declined"));

        assertThrows(GatewayException.class, () -> checkout.checkout(order));
        verify(receipts, never()).send(any(), any());
    }
}

Common mistake

Mixing argument matchers with plain values in one call, such as charge(anyLong(), "ORD-1"). Mockito throws an error; wrap the plain value as eq("ORD-1").

Under the hood

Too many mocks and verifications tie tests to implementation details, so every refactor breaks them. Prefer checking outcomes (return values, state) and verify only the interactions that are the point of the behaviour, such as "a receipt was sent". For code that talks to a real database or HTTP API, integration tests with Testcontainers or WireMock give more confidence than mocks.

Check yourself

Which Mockito call checks that a method was never called?

How this connects

Part of Job-ready backend developer.

Was this lesson helpful?

Finished reading? Mark it complete to track your progress.