import static org.assertj.core.api.Assertions.assertThat;
import javax.sql.DataSource;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.MySQLContainer;
import com.zaxxer.hikari.HikariDataSource;
@SpringBootTest
public class ApplicationTests {
@Autowired
private DataSource dataSource;
@Test
void test() {
assertThat(dataSource).isInstanceOfSatisfying(HikariDataSource.class,
ds -> assertThat(ds.getJdbcUrl()).startsWith("jdbc:mysql://"));
}
@TestConfiguration
static class Config {
@Autowired
Environment env;
@Bean
@ServiceConnection
GenericContainer<?> mysql() {
assertThat(env).isNotNull(); // assertion failed
return new MySQLContainer<>("mysql:5.7");
}
}
}
Inject Environment env by method parameter instead works fine.
Remove @ServiceConnection will make field injection works fine but dataSource not wanted.
Comment From: wilkinsona
Thanks for the report, @quaff.
I'm not sure what we can do about this. @ServiceConnection-annotated beans are loaded by an ImportBeanDefinitionRegistrar so that the relevant …ConnectionDetails beans can be defined for the service. This results in the beans being created very early, crucially before auto-wiring has been performed on the containing configuration class.
One option that doesn't solve the problem but that would make the behavior more clear would be to require the methods to be static, failing fast if they're not. This would be a slightly stricter variant of Framework's recommendation for BeanPostProcessor and BeanFactoryPostProcessor:
Also, be particularly careful with BeanPostProcessor and BeanFactoryPostProcessor definitions through
@Bean. Those should usually be declared as static@Beanmethods, not triggering the instantiation of their containing configuration class. Otherwise,@Autowiredand@Valuemay not work on the configuration class itself, since it is possible to create it as a bean instance earlier than AutowiredAnnotationBeanPostProcessor.
Comment From: snicoll
@philwebb can you share the outcome of the discussion? I am concerned about the getBean call in the bean definition phase.
Comment From: philwebb
The main outcome was we want to remove the call, but we're not sure how yet.
Comment From: philwebb
It's possible that the future direction of Testcontainers will further decouple the container definition from a started container. With that in mind, not accessing the Container at all would be best. We should also switch to the parent ContainerState interface if possible.