Search code examples
spring-boottestcontainerstestcontainers-junit5spring-boot-testcontainers

Mapped port can only be obtained after the container is started - Testcontainers with @ServiceConnection and Spring 3.1.4


I'm trying to update my tests to use the latest support for Spring 3.1.4 for testcontainers, which replaces the @DynamicSource annotation with @ServiceConnection as per here . However, I'm getting this error:

Caused by: org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: 
Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: 
Factory method 'dataSource' threw exception with message: 
Mapped port can only be obtained after the container is started

These are my dependencies:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-testcontainers</artifactId>
   <scope>test</scope>
</dependency>
<dependency>
   <groupId>org.testcontainers</groupId>
   <artifactId>junit-jupiter</artifactId>
   <scope>test</scope>
</dependency>
<dependency>
   <groupId>org.testcontainers</groupId>
   <artifactId>postgresql</artifactId>
   <scope>test</scope>
</dependency>

And here my classes:


@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class FollowshipIT extends BasePostgresConfig {

    @LocalServerPort
    private int port;

    ...

}

public class BasePostgresConfig {

    @Container
    @ServiceConnection
    static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:13.5");

}

I tried both with and without keeping an active profile and -test.yml file with DB configs like the one below and annotating my BasePostgresConfig class with @ActiveProfiles("test"), as I had before for my previous configuration, but that didn't work either.

spring:
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: org.testcontainers.jdbc.ContainerDatabaseDriver
    url: jdbc:tc:postgresql:13.5:///helloTalk

Here is the full code for my application.

Thank you.


Solution

  • This works:

    @Testcontainers
    public class BasePostgresConfig {
    
        @Container
        @ServiceConnection
        static PostgreSQLContainer<?> postgres;
    
        static {
            postgres = new PostgreSQLContainer<>("postgres:13.5");
            postgres.start();
        }
    
    }
    

    Perhaps there could be other ways to achieve this, but for this solution I had to start the container in a static block by calling postgres.start().

    About the @TestContainers annotation, the tests pass also without it, but better to leave it there so the containers are closed after the test execution.

    UPDATE

    After some further investigation, I've noticed the need to call postgres.start() seems to be related to the fact the tests have the @TestInstance(Lifecycle.PER_CLASS) annotation, which is used to remove the need for the @BeforeAll method to be static.