3

I have some integration tests, for which I am using Testcontainers. But I have suddenly realized that when my docker container with database for my application is down, all the other tests (excluding the integration tests using Testcontainers) are failing (even the contextLoads() test generated by Spring Boot initializr)

I get:

java.lang.IllegalStateException: Failed to load ApplicationContext at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:132)

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'liquibase' defined in class path resource

[org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguration$LiquibaseConfiguration.class]: Invocation of init method failed; nested exception is liquibase.exception.DatabaseException: com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure

It is obvious that the application wants to connect to the database, and the database container is down.

I've been investigating, but I don't remember ever needing to start a container just for the test/build process of an application, so this problem is new for me. But if there is something done wrong, it could be here, in my AbstractDatabaseIT class:

@ActiveProfiles("test")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@ContextConfiguration(initializers = AbstractDatabaseIT.DockerMySqlDataSourceInitializer.class)
@Testcontainers
public abstract class AbstractDatabaseIT {

    private static final String MYSQL_IMAGE_NAME = "mysql:5.7.24";

    public static final MySQLContainer<?> mySQLContainer = new MySQLContainer<>(MYSQL_IMAGE_NAME);

    static {
        mySQLContainer.start();
    }

    public static class DockerMySqlDataSourceInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

        @Override
        public void initialize(@NotNull ConfigurableApplicationContext applicationContext) {

            Map<String, String> parameters = new HashMap<>();
            parameters.put("command", "--character-set-server=utf8");
            TestPropertySourceUtils.addInlinedPropertiesToEnvironment(
                    applicationContext,
                    "spring.datasource.url=" + mySQLContainer.getJdbcUrl(),
                    "spring.datasource.username=" + mySQLContainer.getUsername(),
                    "spring.datasource.password=" + mySQLContainer.getPassword()
            );
            mySQLContainer.setParameters(parameters);
        }
    }

}

The integration test extend this class:

public class ChallengeIT extends AbstractDatabaseIT {

    @Autowired
    private ChallengeRepository repository;

    // tests here

All the other, non-integration classes have @SpringBootTest annotation, and the dependencies injected using @Autowired (maybe this is a problem here?)

@SpringBootTest
class EthMessageVerifierTest {

    @Autowired
    private EthMessageVerifier ethMessageVerifier;

    // tests here

What am I missing here? I remember seeing the H2 database dependency all around many projects. Should I drop the testcontainers in favour of H2? Or can I somehow create a single testcontainer instance for all the other tests?

1 Answer 1

7

Tests that you annotate with @SpringBootTest try to populate the entire Spring context. This includes all your beans: your web layer, your business logic, your database setup, etc.

Hence all the infrastructure (e.g. messaging queues, remote systems, databases) that you need otherwise to run your entire application also needs to be present for such tests.

So @SpringBootTest also indicates an integration test and you need to provide your database setup as on application start, Spring Boot's auto-configuration tries to configure your DataSource.

For more information, consider this article on @SpringBootTest and this general overview about unit & integration testing with Spring Boot. You don't always have to use @SpringBootTest and can also use one of Spring Boots many test slice annotations to test something in isolation.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.