Hi

We tried to use Spring Boot & TestContainers integration added in Spring Boot 3.1.0.

We used example from the reference documentation:

public interface MyContainers {

    @Container
    MongoDBContainer mongoContainer = new MongoDBContainer("mongo:5.0");

    @Container
    Neo4jContainer<?> neo4jContainer = new Neo4jContainer<>("neo4j:5");

}

So we created an interface with our container declaration:

public interface ProjectContainers {

    @Container
    GenericContainer<?> mysql = new MySQLContainer("mysql:8");

}

Then we created class-configuration:

@TestConfiguration(proxyBeanMethods = false)
@ImportTestcontainers(ProjectContainers.class)
public class ContainerConfiguration {
}

and finally our integration test:

@SpringBootTest(classes = ContainerConfiguration.class)
@Testcontainers
public class OrderServiceTest {

    @Autowired
    OrderService orderService;

    @Test
    void save_success() {
        Order order = new Order();
        orderService.save(order);
    }

However our test failed with exception:

Caused by: org.hibernate.HibernateException: Unable to determine Dialect without JDBC metadata (please set 'javax.persistence.jdbc.url', 'hibernate.connection.url', or 'hibernate.dialect')
    at org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.determineDialect(DialectFactoryImpl.java:188) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
    at org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.buildDialect(DialectFactoryImpl.java:87) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
    at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:274) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
    at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:34) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
    at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:119) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:264) ~[hibernate-core-6.2.2.Final.jar:6.2.2.Final]

Comment From: eddumelendez

Use MySQLContainer<?> mysql = new MySQLContainer<>("mysql:8"); and add @ServiceConnection. Look at the tip at the end of https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#features.testing.testcontainers.at-development-time.importing-container-declarations

Comment From: sergey-morenets

Hi @eddumelendez

Thank you for the quick response. You're correct. Adding @ServiceConnection resolves this issue. However I guess adding code that already has @ServiceConnection makes code examples more obvious and clear.

The same relates to declaring containers as Spring beans. Here's an example from the documentation:

@TestConfiguration(proxyBeanMethods = false)
public class MyContainersConfiguration {

    @Bean
    public MongoDBContainer monogDbContainer(DynamicPropertyRegistry properties) {
        MongoDBContainer container = new MongoDBContainer("mongo:5.0");
        properties.add("spring.data.mongodb.host", container::getHost);
        properties.add("spring.data.mongodb.port", container::getFirstMappedPort);
        return container;
    }
}

The documentation states that "A typical configuration would look like this". However Spring Boot fails to use it because it doesn't have @ServiceConnection annotation on the bean declaration.

Comment From: eddumelendez

Are you using it at development time just like the docs state? If no, keep using

@DynamicPropertySource
static void properties(DynamicPropertyRegistry registry) {
        registry.add("spring.data.mongodb.host", container::getHost);
        registry.add("spring.data.mongodb.port", container::getFirstMappedPort);
}

I think there is a confusion about the different usage

Comment From: wilkinsona

In the docs, we don't know how MyContainers will be used. You could make your test class implement MyContainers and then reference those containers in a @DynamicPropertySource. Alternatively, you might need @ServiceConnection. The tip at the end of this section is intended to address that.

That said, this has caused some confusion before so we probably need to do something here, I'm just not quite sure what.

/cc @quaff

Comment From: quaff

@wilkinsona I think we should add @ServiceConnection, and add a tip states that it could be removed if @DynamicPropertySource is using.