I'm using Spring-boot 2.5.3 with Junit 5
I am trying to test with a PostgresSQL test container. I need to use this same test container with integration test and repository test because it was having two instances in Docker.
Here is my base class where I initialize the container.
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.PostgreSQLContainer;
public class PostgresTestContainer {
static final PostgreSQLContainer postgreSQLContainer;
static {
postgreSQLContainer = (PostgreSQLContainer) new PostgreSQLContainer("postgres:12")
.withDatabaseName("test")
.withUsername("postgres")
.withPassword("postgres")
.withReuse(true);
postgreSQLContainer.start();
}
@DynamicPropertySource
static void datasourceConfig(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgreSQLContainer::getJdbcUrl);
registry.add("spring.datasource.password", postgreSQLContainer::getPassword);
registry.add("spring.datasource.username", postgreSQLContainer::getUsername);
}
}
This is repository test.
@RunWith(SpringRunner.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class CustomerRepositoryTest extends PostgresTestContainer {
@Autowired
private CustomerRepository customerRepository;
@Test
@Sql("/scripts/import.sql")
public void findAllShouldGetAllCustomers() {
List<Customer> foundCustomers = customerRepository.findAll();
assertThat(foundCustomers).isNotNull();
assertThat(foundCustomers.size()).isEqualTo(3);
}
}
This is another place where I need to use the same test container.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class BasicIT extends PostgresTestContainer {
@Autowired
private TestRestTemplate testRestTemplate;
@MockBean
private CustomerRepository customerRepository;
@Test
void shouldFailFetchingCustomersWhenDatabaseIsDown() {
when(customerRepository.findAll()).thenThrow(new RuntimeException("Cannot connect to database."));
ResponseEntity<String> result = this.testRestTemplate
.exchange("/api/v1/customers", HttpMethod.GET, HttpEntity.EMPTY, String.class);
assertEquals(500, result.getStatusCodeValue());
}
@Test
public void shouldFetchAListOfCustomers(){
ResponseEntity<List<Customer>> result = this.testRestTemplate
.exchange("/api/v1/customers", HttpMethod.GET, HttpEntity.EMPTY, new ParameterizedTypeReference<>() {});
assertEquals(200, result.getStatusCodeValue());
}
}
Running:
mvn clean install
This works, and all tests run.
But it opens two containers as shown in Docker image here.
How to use singleton container the correct way? I want to use only one.
As you can see from the container image names, the containers are different. The second container is your database (postgres
), but the first one (ryuk
) is an auxillary container, started by the Testcontainer
library itself by default. Ryuk
performs fail-safe cleanup of other containers (documentation) after they are not needed anymore. There is no need to worry about it, because it's tiny (~5Mb).
If you absolutelly sure that you don't need it, you can disable ryuk
following this instruction.