Loslegen
Javaneer
Zurück zur Stufe
Stufe 6·Professionelles Java

Testing

JUnit 5, AssertJ, Mockito, the TDD cycle, the test pyramid, and integration testing.

20 Min. LesezeitFortgeschritten

Deutsche Übersetzung in Arbeit

Diese Lektion ist noch nicht ins Deutsche übersetzt und wird daher auf Englisch angezeigt. Der Rest der Seite ist vollständig lokalisiert.

Auf dieser Seite

Code without tests is code you're afraid to change. Automated tests verify your program works and keep it working as it grows. Testing is a core professional skill - and once you have a safety net, you'll refactor fearlessly.

Why test?

Tests are like a safety net for a trapeze artist

The net doesn't perform the act - but it lets the artist attempt bold moves without fear, because a slip won't be catastrophic. Automated tests are that net: they let you change and improve code confidently, catching mistakes the instant they happen instead of in production.

Your first test with JUnit 5

JUnit is the standard Java testing framework. A test is just a method annotated with @Test that checks an expected outcome with assertions.

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class CalculatorTest {

    @Test
    void addsTwoNumbers() {
        Calculator calc = new Calculator();
        int result = calc.add(2, 3);
        assertEquals(5, result);      // fails loudly if result isn't 5
    }
}

If add ever breaks, this test fails immediately and tells you exactly what went wrong.

The Arrange-Act-Assert pattern

Structure each test in three clear steps:

@Test
void withdrawReducesBalance() {
    Account account = new Account(100);   // Arrange: set up
    account.withdraw(30);                 // Act: do the thing
    assertEquals(70, account.balance());  // Assert: check the result
}

Better assertions with AssertJ

AssertJ offers fluent, readable assertions that read like English:

import static org.assertj.core.api.Assertions.assertThat;

assertThat(result).isEqualTo(5);
assertThat(names).contains("Ada").hasSize(3);
assertThat(user.email()).endsWith("@example.com");

Mocking dependencies with Mockito

To test a class in isolation, you replace its real dependencies with mocks - fake stand-ins you control. Mockito is the standard tool.

import static org.mockito.Mockito.*;

@Test
void sendsWelcomeEmail() {
    EmailService email = mock(EmailService.class);   // a fake
    var service = new SignupService(email);

    service.register("ada@example.com");

    verify(email).send("ada@example.com", "Welcome!");  // was it called?
}
A mock is like a crash-test dummy

You don't test a car's airbag with a real person - you use a dummy you fully control and observe. A mock is a stand-in for a real dependency (a database, an email server) that you program to behave predictably and inspect afterward.

Test-Driven Development (TDD)

TDD flips the usual order: write the test first, watch it fail, then write just enough code to pass. The rhythm is Red → Green → Refactor:

  1. Red - write a failing test for the behavior you want.
  2. Green - write the simplest code that makes it pass.
  3. Refactor - clean up, tests still green.

TDD designs as it tests

Writing the test first forces you to think about how your code will be used before you build it - which tends to produce simpler, better-designed APIs. Even if you don't do strict TDD, writing tests early beats bolting them on later.

The test pyramid

Aim for many fast, focused tests and few slow, broad ones:

LevelWhat it testsQuantity
UnitOne class/method in isolationMany (fast)
IntegrationParts working together (e.g. with a real DB)Some
End-to-endThe whole system through the UI/APIFew (slow)

Test behavior, not implementation

Good tests check what the code does (its observable behavior), not how it does it internally. Tests tied to internal details break every time you refactor - even when nothing actually broke. Test the contract, not the plumbing.

Quick check

What is the correct order of the Test-Driven Development cycle?

Key takeaways

  • Automated tests verify behavior and let you change code confidently.
  • JUnit 5 tests are @Test methods using assertions; structure them Arrange-Act-Assert.
  • AssertJ gives fluent, readable assertions; Mockito replaces dependencies with controllable mocks.
  • TDD writes tests first in a Red-Green-Refactor cycle, improving design.
  • Follow the test pyramid: many fast unit tests, some integration, few end-to-end.
  • Test observable behavior, not internal implementation details.

Now that you can test, let's automate building and packaging your project with build tools.