Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Yes, it is possible to launch multiple instances of PostgreSQL using Spring Boot Testcontainers. This can be achieved by creating multiple test classes, each with their own Testcontainer instance of PostgreSQL.

For example, let's say we have two test classes - FooTest and BarTest - and we want to launch two instances of PostgreSQL for each of them. Here's how we can do it:

FooTest class:

@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(initializers = {FooTest.Initializer.class})
public class FooTest {

    @Container
    private static PostgreSQLContainer<?> pgContainer1 = new PostgreSQLContainer<>("postgres:13");

    @ClassRule
    public static PostgreSQLContainer<?> pgContainer2 = new PostgreSQLContainer<>("postgres:13")
            .withDatabaseName("testdb2")
            .withUsername("testuser2")
            .withPassword("testpass2");

    static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
        public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
            TestPropertyValues.of(
                    "spring.datasource.url=" + pgContainer1.getJdbcUrl(),
                    "spring.datasource.username=" + pgContainer1.getUsername(),
                    "spring.datasource.password=" + pgContainer1.getPassword(),

                    "spring.second-datasource.url=" + pgContainer2.getJdbcUrl(),
                    "spring.second-datasource.username=" + pgContainer2.getUsername(),
                    "spring.second-datasource.password=" + pgContainer2.getPassword()
            ).applyTo(configurableApplicationContext.getEnvironment());
        }
    }

    // Tests go here
}

BarTest class:

@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(initializers = {BarTest.Initializer.class})
public class BarTest {

    @Container
    private static PostgreSQLContainer<?> pgContainer1 = new PostgreSQLContainer<>("postgres:13");

    @ClassRule
    public static PostgreSQLContainer<?> pgContainer2 = new PostgreSQLContainer<>("postgres:13")
            .withDatabaseName("testdb2")
            .withUsername("testuser2")
            .withPassword("testpass2");

    static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
        public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
            TestPropertyValues.of(
                    "spring.datasource.url=" + pgContainer1.getJdbcUrl(),
                    "spring.datasource.username=" + pgContainer1.getUsername(),
                    "spring.datasource.password=" + pgContainer1.getPassword(),

                    "spring.second-datasource.url=" + pgContainer2.getJdbcUrl(),
                    "spring.second-datasource.username=" + pgContainer2.getUsername(),
                    "spring.second-datasource.password=" + pgContainer2.getPassword()
            ).applyTo(configurableApplicationContext.getEnvironment());
        }
    }

    // Tests go here
}

Notice that we're using the @ClassRule annotation to create a second instance of PostgreSQL in each test class. We're also using the @Container annotation to create the first instance of PostgreSQL.

In the Initializer class, we're setting the properties for both data sources (spring.datasource and spring.second-datasource) using TestPropertyValues, which allows us to pass the JDBC URL, username, and password for each instance of PostgreSQL.

With this setup, we can run both FooTest and BarTest concurrently, and each test class will have its own instances of PostgreSQL running.