Testing
JUnit 5, AssertJ, Mockito, the TDD cycle, the test pyramid, and integration testing.
On this page
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?
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?
}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:
- Red - write a failing test for the behavior you want.
- Green - write the simplest code that makes it pass.
- 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:
| Level | What it tests | Quantity |
|---|---|---|
| Unit | One class/method in isolation | Many (fast) |
| Integration | Parts working together (e.g. with a real DB) | Some |
| End-to-end | The whole system through the UI/API | Few (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.