Loading published curriculum…

18 · Testing the complete backend / LESSON 89 OF 102

Mockito, fakes, and dependency boundaries

A test double replaces an external collaboration so the test can control its behavior.

Before this lesson: JUnit lifecycle and parameterized tests

Understand the topic

Use mocks for interactions that matter to the contract and simple fakes for in-memory behavior. Do not mock the class under test or every value object. Excessive verification of private implementation steps makes harmless refactoring break tests.

Stub both success and failure paths. Verify absence of a write when validation fails, because that side effect is part of the contract. Keep integration tests for the seams that mocks cannot validate, such as SQL mappings and serialization.

EXAMPLE · JAVA

NotificationTest.java

import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.*;
class NotificationTest {
 interface Sender { void send(String message); }
 record Reminder(Sender sender) { void remind() { sender.send("Review Java"); } }
 @Test void sendsTheRequiredReminder() {
  Sender sender = mock(Sender.class);
  new Reminder(sender).remind();
  verify(sender).send("Review Java");
 }
}

What to expect

The interaction is the required output of this small service. This test does not prove email delivery or external provider behavior.

YOUR TURN

Put it into practice

  1. 01Test a service using a repository double.
  2. 02Make the repository fail and assert the service does not emit a success notification.
  3. 03Verify: The failure-path test catches a false success and does not require a live database.

Pass a quiz or complete a lab to check today’s streak. Each lesson counts once per day, including when you review it later.

UNDER THE HOOD

Build the mental model

A test double replaces an external collaboration so the test can control its behavior.

  1. 01Use mocks for interactions that matter to the contract and simple fakes for in-memory behavior. Do not mock the class under test or every value object. Excessive verification of private implementation steps makes harmless refactoring break tests.
  2. 02Stub both success and failure paths. Verify absence of a write when validation fails, because that side effect is part of the contract. Keep integration tests for the seams that mocks cannot validate, such as SQL mappings and serialization.
  3. 03Trace the example: The interaction is the required output of this small service. This test does not prove email delivery or external provider behavior.

A mistake worth avoiding

A service test stays green after the real SQL query is broken.

DEBUGGING ROOM

Something broke. Where do you look?

A service test stays green after the real SQL query is broken.

Before revealing the diagnosis, write down your first investigation step.

CHECK YOUR UNDERSTANDING

Can a mocked repository test prove its SQL is valid?

Choose one answer

BUILD IT YOURSELF

Test a service using a repository double.

  1. 1.Test a service using a repository double.
  2. 2.Make the repository fail and assert the service does not emit a success notification.
  3. 3.Reproduce this failure, then repair it: A service test stays green after the real SQL query is broken.

Acceptance checklist

Lab completion is your self-report. Knowledge checks do not certify project quality.

RETRIEVE IT FROM MEMORY

Can a mocked repository test prove its SQL is valid?

Revisit this lesson in three days after a successful check or lab.

Ready for the next step?

The failure-path test catches a false success and does not require a live database.

Reading is separate from passing a knowledge check or completing a lab.

Go deeper · official references