Yury
Yury

Reputation: 1

When i try to test with Testcontainers more than one TestClass, others always failed

The problem is: When i try to use singleton-testcontainer, all my testclasses after first failed by assertions. It means, that even if i see in log that my scenarios was comlete success, Assertions always failed.

The fact is, when i use @Testcontainers and @Container annotation - it's all good.

My first test class.

@SpringBootTest(classes = {ContractSpringBootApplication.class})
@ExtendWith({MockitoExtension.class, OutputCaptureExtension.class})
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@ActiveProfiles("test")
public class UpdateMergeTest extends AbstractTestcontainersTest {

    @SpyBean
    @Autowired
    private TechMergeUpdateRepo techMergeUpdateRepo;
    
    @BeforeEach
     void clean() {
        techMergeUpdateRepo.deleteAll();
    }

My second test class. (does the same things, but used more repositories)

@SpringBootTest(classes = {ContractSpringBootApplication.class})
@ExtendWith({MockitoExtension.class, OutputCaptureExtension.class})
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@ActiveProfiles("test")
public class UpdateEntityTest extends AbstractTestcontainersTest {

    @SpyBean
    @Autowired
    private TechMergeUpdateRepo techMergeUpdateRepo;
    
    @SpyBean
    @Autowired
    private UpdateEntityRepo updateEntityRepo;
    

    @BeforeEach
     void clean() {
        techMergeUpdateRepo.deleteAll();
        updateEntityRepo.deleteAll();
    }

My "singleton" testcontainer class.

public abstract class AbstractTestcontainersTest {
    private final static String DATABASE_NAME = "test_name";

    public static final PostgreSQLContainer<?> postgresContainer = new PostgreSQLContainer<>("postgres:12")
            .withReuse(true)
            .withDatabaseName(DATABASE_NAME);

    static {

        postgresContainer.start();

    }
    
    @DynamicPropertySource
    public static void overrideProps(DynamicPropertyRegistry registry) {
        registry.add("spring.datasource.url", postgresContainer::getJdbcUrl);
        registry.add("spring.datasource.username", postgresContainer::getUsername);
        registry.add("spring.datasource.password", postgresContainer::getPassword);
        registry.add("spring.datasource.driver-class-name", postgresContainer::getDriverClassName);
    }


}

After tests i always get this: enter image description here

BUT!

If I change my AbstractTestcontainersTest for:

@Slf4j
@Testcontainers
public abstract class AbstractTestcontainersTest {

    private final static String DATABASE_NAME = "test_name";

    @Container
    public static final PostgreSQLContainer<?> postgresContainer = new PostgreSQLContainer<>("postgres:12")
            .withReuse(true)
            .withDatabaseName(DATABASE_NAME);

    static {
        postgresContainer.start();
      
    }

    @DynamicPropertySource
    public static void overrideProps(DynamicPropertyRegistry registry) {
        registry.add("spring.datasource.url", postgresContainer::getJdbcUrl);
        registry.add("spring.datasource.username", postgresContainer::getUsername);
        registry.add("spring.datasource.password", postgresContainer::getPassword);
        registry.add("spring.datasource.driver-class-name", postgresContainer::getDriverClassName);

    }


}

It will start working correctly.

enter image description here

I checked the log output. The feeling is that the problem is somewhere in the “underrun” of Spring tests, in test classes, starting from the second. I checked the logs - my “scenarion” is fully completed and works correctly, but the assertions are falling

I checked the log output. The feeling is that the problem is somewhere in the “underrun” of Spring tests, in test classes, starting from the second.

Upvotes: 0

Views: 824

Answers (2)

kiuby_88
kiuby_88

Reputation: 354

I guess you are trying to reuse the same containers for all the tests that extends your abstract integration test. You can fin documentation about the singleton pattern here. I seems you are mixing both automatic and manual lifecycle management. @TestContainer and @Container annotations, will create, start, and stop the container according to the test classes and spring context, but you would potentially have one container per class (that extends Abstract Integration Test). Maybe singleton pattern is working because you have configured the reuse flag.

You can manage the lifecycle of the container using the static block to start the container, as you did, but AFAIK it isn't compatible with @TestContainer and @Container annotation.

So, you can try the following:

@Slf4j
public abstract class AbstractTestcontainersTest {

    private final static String DATABASE_NAME = "test_name";

    public static final PostgreSQLContainer<?> postgresContainer = new PostgreSQLContainer<>("postgres:12")
            .withDatabaseName(DATABASE_NAME);

    static {
        postgresContainer.start();
      
    }

    @DynamicPropertySource
    public static void overrideProps(DynamicPropertyRegistry registry) {
        registry.add("spring.datasource.url", postgresContainer::getJdbcUrl);
        registry.add("spring.datasource.username", postgresContainer::getUsername);
        registry.add("spring.datasource.password", postgresContainer::getPassword);
        registry.add("spring.datasource.driver-class-name", postgresContainer::getDriverClassName);

    }
}

Please, note the @DynamicPropertySource can be drop if you are using SpringBoot 3.X, see here

Upvotes: 0

Yury
Yury

Reputation: 1

The problem was using @SpyBean annotations.

Because the context was not re-raised completely, in the case of a singleton test container. When asserting, all @SpyBeans after the first class pointed to Proxy without explicit proxying.

Moving the @SpyBean annotated injections to the base class (AbstractTestcontainersTest) solved the problem.

Upvotes: 0

Related Questions