Testing Fundamentals
Use this page to revise the vocabulary behind automated testing.
Why automated tests exist
Automated tests exist to prevent regressions (a change breaking something that used to work), to document behaviour (a test shows what the code is supposed to do), and to enable safe refactoring (you can change how code works internally and immediately know if you broke anything).
The test pyramid
- Unit tests — small, fast, isolated tests of one function or class in isolation.
- Integration tests — test that multiple components work correctly together (e.g. a controller and a service, or a UI component and a mocked API).
- End-to-end (E2E) tests — test a full user flow through the real (or a realistic) system; slower and more brittle, so used sparingly.
Writing a unit test
The standard structure is arrange-act-assert: set up the situation, perform the action being tested, then assert the expected outcome. Good test names describe behaviour ("returns an error for an empty username"), not implementation ("test1").
Test-first thinking and coverage
A test-first (TDD) mindset means writing a test before, or alongside, the code it verifies, using the test to clarify what "correct" means before you build it. Code coverage measures which lines or branches of code were executed by your tests — a useful signal, but not a guarantee: 100% coverage only means every line ran at least once, not that the assertions checking it are any good.
Starting Points
- Test-Driven Development with Java. O'Reilly.
- Testing fundamentals
Key Points
- You can explain why automated tests matter: regressions, documentation, safe refactoring.
- You can explain the difference between unit, integration, and end-to-end tests.
- You can structure a test using arrange-act-assert and name it after the behaviour it checks.
- You can explain what code coverage measures, and why high coverage doesn't guarantee good tests.