Search code examples
javaspring-data-jpatestcontainers

Spring Boot TestContainers Mapped port can only be obtained after the container is started


I'm trying to add automated testing using the TestContainers library to my Spring Boot project

Here is my test class to test my jpa repository:

package com.ubm.mfi.repo;

import com.ubm.mfi.domain.MasterFileIndexRow;
import org.junit.ClassRule;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Testcontainers;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

@ExtendWith(SpringExtension.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Testcontainers
@ContextConfiguration(initializers = { MasterFileIndexRowRepoTest.Initializer.class })
public class MasterFileIndexRowRepoTest {

    @ClassRule
    public static PostgreSQLContainer<?> postgreSQLContainer = new PostgreSQLContainer<>("postgres:latest");

    @Autowired
    private MasterFileIndexRowRepo masterFileIndexRowRepo;

    // write test cases here
    @Test
    public void whenFindAllRows_thenSizeIsGreaterThanZero() {
        // when
        List<MasterFileIndexRow> rows = masterFileIndexRowRepo.findAll();

        // then
        assertThat(rows.size())
                .isGreaterThan(0);
    }

    static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

        @Override
        public void initialize(ConfigurableApplicationContext configurableApplicationContext) {

            TestPropertyValues
                    .of("spring.datasource.url=" + postgreSQLContainer.getJdbcUrl(),
                            "spring.datasource.username=" + postgreSQLContainer.getUsername(),
                            "spring.datasource.password=" + postgreSQLContainer.getPassword())
                    .applyTo(configurableApplicationContext.getEnvironment());

        }

    }

}

Here are the dependencies in my build.gradle

testCompile "org.testcontainers:testcontainers:1.14.1"
testCompile "org.testcontainers:postgresql:1.14.1"

When running the Test I get this error: Caused by: java.lang.IllegalStateException: Mapped port can only be obtained after the container is started

From what I've seen, the container should start when starting the test, does anybody know what I'm missing?


Solution

  • You are trying to use PostgresSQLContainer as JUnit ClassRule but your usage of @ExtendWith seems to indicate that you are using JUnit 5 / Jupiter which does not support JUnit 4 rules.

    Use the JUnit 5 integration of Testcontainers instead: https://www.testcontainers.org/test_framework_integration/junit_5/