Testcontainers loss of connection after some tests running
Asked Answered
B

3

5

I'm using testcontainer in my oss software but i think there is a problem in my configurations or in the docker/testcontainer runtime...

I have some tests and when they are running separated, everything works fine but when I try to run all tests the last on fail due to a problem when the application try to connect with the container..

Debuggingthe problem I found that the container started in one port but the application is trying connection in other port, most of then are used in the last test classes run

All tests running:

tests failing

One of the failed tests show me this log:

log of failed test

And the container started when the class UserControllerTest started is using another port, like this:

docker on windows showing the container port

My test configuration is based in an abstract class (see bellow) and, like a said, if a run the class who is showing errors alone, everything works fine.

@Testcontainers
@ActiveProfiles("test")
@ExtendWith(SpringExtension::class)
@TestMethodOrder(value = OrderAnnotation::class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
abstract class AbstractTest {

    companion object {

        @Container
        private val redisContainer = GenericContainer<Nothing>("redis:6-alpine")
            .apply {
                withExposedPorts(6379)
                withCreateContainerCmdModifier { cmd -> cmd.withName("wb-test-cache") }
            }

        @Container
        private val postgresContainer = PostgreSQLContainer<Nothing>("postgres:13-alpine")
            .apply {
                withExposedPorts(5432)
                withUsername("sa_webbudget")
                withPassword("sa_webbudget")
                withDatabaseName("webbudget")
                withCreateContainerCmdModifier { cmd -> cmd.withName("wb-test-database") }
            }

        @JvmStatic
        @DynamicPropertySource
        fun dynamicPropertiesRegister(registry: DynamicPropertyRegistry) {
            registry.add("spring.datasource.url", postgresContainer::getJdbcUrl)
            registry.add("spring.redis.host", redisContainer::getHost)
            registry.add("spring.redis.port", redisContainer::getFirstMappedPort)
        }
    }
}

Someone have seen something like this an know how to solve it?

Bucky answered 5/8, 2021 at 2:59 Comment(0)
B
15

After some research I figured out what is the problem: the context.

When spring runs the first mvc controller test, it starts a single instance of tomcat to all controllers, this means when testcontainers recreate the docker instance for the database (after a new controller start testing) the properties (port, URL..) were not updated because spring will reuse the current instance of tomcat (from the last mvc test)

Solution: mark the context as dirty for each test class, this will make spring recreate the context everytime a new test class starts and this will trigger the dynamicPropertiesRegister to update the properties correctly.

I just had to add this annotation @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) to my AbstractTest

Bucky answered 31/8, 2021 at 4:4 Comment(0)
G
2

According to the documentation:

Containers declared as static fields will be shared between test methods. They will be started only once before any test method is executed and stopped after the last test method has executed. Containers declared as instance fields will be started and stopped for every test method.

So perhaps you're containers are relaunched for every test and get new port numbers?

See: https://www.testcontainers.org/test_framework_integration/junit_5/

We run a setup similar to what you want to accomplish, but are instead using a @ContextConfiguration( initializers = [ in the abstract class with a list of initializers where each container is configured and added to the shared ConfigurableApplicationContext. But your approach seems a lot simpler if you can make it work using only the annotations.

Goodall answered 18/8, 2021 at 15:13 Comment(0)
O
-1

You want to start container for reuse. Put this to the chain of methods:

.withReuse(true);
Oresund answered 9/8, 2021 at 3:23 Comment(1)
It's not about the reuse of the container, I want a new container when every test class runs.. The problem is: in the last test class, the container port is not getting set properly and the application doesn't start because spring can't connect to database or redisBucky

© 2022 - 2024 — McMap. All rights reserved.