Testing a service you cannot run alone
Push each kind of bug down to the cheapest layer of test that can still catch it.
Open this lesson in the learning hubKey points
- Most of your tests should be plain unit tests over your own logic. No Spring context, no Docker, milliseconds each.
- Slices cover the edges:
@WebMvcTestfor controllers,@DataJpaTestfor repositories. Everything else is mocked. - Testcontainers starts a real Postgres or Kafka for the test. A mocked repository will never catch invalid SQL.
- Stub the services you call with WireMock or
MockRestServiceServer. Never let a build call a live dependency. - Keep end-to-end tests few and boring. They are slow, flaky, and they usually fail for a reason that is not your bug.
Example
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@Testcontainers
class OrderFlowTest {
// A real database for the duration of the class.
@Container
static PostgreSQLContainer<?> db = new PostgreSQLContainer<>("postgres:16");
// Docker picks the port, so the properties are wired in at runtime.
@DynamicPropertySource
static void datasource(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", db::getJdbcUrl);
registry.add("spring.datasource.username", db::getUsername);
registry.add("spring.datasource.password", db::getPassword);
}
@Autowired
TestRestTemplate http;
@Test
void placesAnOrderAgainstARealSchema() {
// inventory is a WireMock stub; only the database is real.
ResponseEntity<OrderView> res =
http.postForEntity("/api/orders", new NewOrder("JCH-9", 1), OrderView.class);
assertThat(res.getStatusCode()).isEqualTo(HttpStatus.CREATED);
assertThat(res.getBody().status()).isEqualTo("PLACED");
}
}
Fake what you do not own, run for real what you do, and keep end-to-end tests rare.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Microservices course, and every lesson in it is listed on the Microservices contents page.