JUnit 5 lifecycle callbacks
When testing with Testcontainers, you want to start the required containers
before executing any tests and remove them afterwards. You can use JUnit 5
@BeforeAll and @AfterAll lifecycle callback methods for this:
package com.testcontainers.demo;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.List;
import java.util.Optional;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.testcontainers.postgresql.PostgreSQLContainer;
class CustomerServiceWithLifeCycleCallbacksTest {
static PostgreSQLContainer postgres = new PostgreSQLContainer(
"postgres:16-alpine"
);
CustomerService customerService;
@BeforeAll
static void startContainers() {
postgres.start();
}
@AfterAll
static void stopContainers() {
postgres.stop();
}
@BeforeEach
void setUp() {
customerService =
new CustomerService(
postgres.getJdbcUrl(),
postgres.getUsername(),
postgres.getPassword()
);
customerService.deleteAllCustomers();
}
@Test
void shouldCreateCustomer() {
customerService.createCustomer(new Customer(1L, "George"));
Optional<Customer> customer = customerService.getCustomer(1L);
assertTrue(customer.isPresent());
assertEquals(1L, customer.get().id());
assertEquals("George", customer.get().name());
}
@Test
void shouldGetCustomers() {
customerService.createCustomer(new Customer(1L, "George"));
customerService.createCustomer(new Customer(2L, "John"));
List<Customer> customers = customerService.getAllCustomers();
assertEquals(2, customers.size());
}
}Here's what the code does:
PostgreSQLContaineris declared as a static field. The container starts before all tests and stops after all tests in this class.@BeforeAllstarts the container,@AfterAllstops it.@BeforeEachinitializesCustomerServicewith the container's JDBC parameters and deletes all rows to give each test a clean database.
Key observations:
- Because the container is a static field, it's shared across all test
methods in the class. You can declare it as a non-static field and use
@BeforeEach/@AfterEachto start a new container per test, but this isn't recommended as it's resource-intensive. - Even without explicitly stopping the container in
@AfterAll, Testcontainers uses the Ryuk container to clean up containers automatically when the JVM exits.