28

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?

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
Will Harrison
  • 565
  • 3
  • 8
  • 21
  • this error may be induced by another error -> https://github.com/testcontainers/testcontainers-java/issues/3609 Check if you have "Could not connect to Ryuk at localhost:49154" in your logs. – naXa stands with Ukraine Dec 28 '21 at 01:19
  • I also had this issue when I had forgotten to use the `@Testcontainers` annotation on the class – ndtreviv Apr 06 '23 at 17:42

3 Answers3

20

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/

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
  • 3
    Alternatively, the JDBC integration can be used: https://www.testcontainers.org/modules/databases/jdbc/ – bsideup May 06 '20 at 10:14
7

Not sure if it does help to smdy but for me starting the actual test container after its definition solved the problem:

@Container
private static final PostgreSQLContainer DATABASE = new PostgreSQLContainer("postgres:14");

static {
    DATABASE.start();
}

// any kind of DynamicPropertySources or initializers 
// goes below and can successfully get mapped port from DATABASE.getJdbcUrl()
Dzmitry Hubin
  • 1,091
  • 12
  • 14
1

This problem occured when I still used Junit 4 org.junit.Test to annotate test methods. Adding the explicit start command as suggested by Dzmitry worked for me in this case. As the more appropriate remediation, I annotated my test methods with Junit 5 org.junit.jupiter.api.Test annotation. In this case, the containers start without an explicit start command.

Below worked for me

import org.junit.jupiter.api.Test;

import org.testcontainers.containers.PostgreSQLContainer;

import org.testcontainers.junit.jupiter.Container;

import org.testcontainers.junit.jupiter.Testcontainers;

@Testcontainers
public class DataBaseConnectionTest {

    @Container
    private static final PostgreSQLContainer<?> databaseContainer = new PostgreSQLContainer<>("postgres:14");

    ...
    @Test
    void test1() {
    System.out.println(databaseContainer..getJdbcUrl());
    }

}

The following are my Maven dependencies:

    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.9.1</version>
        <scope>test</scope>
    </dependency>
    
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <version>5.9.1</version>
        <scope>test</scope>
    </dependency>
    
    <dependency>
        <groupId>org.testcontainers</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>1.17.5</version>
        <scope>test</scope>
    </dependency>
   
    <dependency>
        <groupId>org.testcontainers</groupId>
        <artifactId>testcontainers</artifactId>
        <version>1.17.5</version>
        <scope>test</scope>
    </dependency>
    
    <dependency>
        <groupId>org.testcontainers</groupId>
        <artifactId>postgresql</artifactId>
        <version>1.17.5</version>
        <scope>test</scope>
    </dependency>
Jannick
  • 11
  • 2