| name | testing |
| description | Use when creating, modifying, debugging, or discussing automated tests,
including test strategy, coverage, integration testing, and testing
anti-patterns.
|
| license | CC-BY-NC-SA-4.0 |
| metadata | {"copyright":"Caleb Cushing"} |
Testing
Guidelines for writing effective automated tests.
Philosophy: Prefer Sociable and Integration Tests
Follow the testing trophy approach - value sociable and integration tests over solitary unit tests with mocks.
Sociable Tests
- Use real collaborating objects, not mocks
- Test the unit under test with its real dependencies
- Assume collaborators work correctly (they have their own tests)
- Tests behavior as the system actually runs
Integration Tests
- Verify independently developed units work together correctly
- Prefer narrow integration tests: test one integration point at a time
- Use test doubles (stubs/fakes) for external services
- Avoid broad integration tests that require live versions of all services
Solitary Tests (avoid)
- Replace all collaborators with mocks/stubs
- Creates brittle tests that break during refactoring
- Tests implementation details rather than behavior
When to Use Test Doubles
No mocks. Prefer real collaborators. Use test doubles only when a real collaborator is impractical.
Prefer real collaborators
Sociable tests use real objects for all internal collaborators. Use dependency inversion to make non-deterministic concerns testable with real, controlled implementations:
- Randomness — inject a
Supplier, function, or equivalent. In tests, pass () -> 42.
- Time — inject a
Clock, function, or equivalent. In tests, pass a fixed clock.
- Configuration — pass values or configuration objects directly.
This is not mocking; it is wiring a real dependency with a controlled implementation.
Use stubs/fakes only for non-invertable boundaries
When a real collaborator cannot be used directly, use stubs/fakes:
- Standard input/output — prefer injectable streams/writers over mocking global
stdin/stdout.
- Third-party network services / external services you don't control — e.g., HTTP APIs, cloud services; use stubs/fakes such as WireMock or in-memory fakes, not interaction-verifying mocks.
Anti-patterns
Over-mocked tests:
@Test
void processOrder() {
var mockRepo = mock(OrderRepo.class);
var mockNotifier = mock(Notifier.class);
var service = new OrderService(mockRepo, mockNotifier);
when(mockRepo.find(any())).thenReturn(fakeOrder);
service.process(orderId);
verify(mockNotifier).send(any());
}
Testing implementation details:
@Test
void parserSetsStateCorrectly() {
var parser = new Parser();
parser.parse("input");
assertThat(parser.getTokenCount()).isEqualTo(3);
}
Testing trivial code:
@Test
void getterReturnsValue() {
var person = new Person("Alice");
assertThat(person.getName()).isEqualTo("Alice");
}
Trivial code should be exercised by other tests, not explicitly tested. If it isn't covered, question whether it's needed (libraries may need explicit tests to hit coverage targets).
Correct Approaches
Sociable test with real collaborators:
@Test
void processOrderSendsNotification() {
var database = new TestDatabase();
var emailClient = new FakeEmailClient();
var service = new OrderService(database, emailClient);
service.process(orderId);
assertThat(emailClient.wasNotified(customerEmail)).isTrue();
}
Integration test through public API:
@Test
void checkoutFlow() {
var app = new Application(testConfig);
var result = app.checkout(CreateOrderRequest.builder().item("book").quantity(2).build());
assertThat(result.status()).isEqualTo(OrderStatus.CONFIRMED);
assertThat(result.confirmationNumber()).isNotNull();
}
Narrow integration test with stub:
@Test
void fetchesWeatherFromApi() {
var weatherStub = new WireMockServer();
weatherStub.stubFor(get("/api/weather").willReturn(okJson(weatherResponse)));
var client = new WeatherClient(weatherStub.baseUrl());
var result = client.fetchWeather();
assertThat(result.temperature()).isEqualTo(72);
}
Test Structure
Use "Arrange, Act, Assert" (or Given/When/Then):
- Set up test data and context
- Invoke the method under test
- Verify expected outcomes
References