I am using docker/testcontainers to run a postgresql db for testing. I have effectively done this for unit testing that is just testing the database access. However, I have now brought springboot testing into the mix so I can test with an embedded web service and I am having problems.
The issue seems to be that the dataSource bean is being requested before the container starts.
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [com/myproject/integrationtests/IntegrationDataService.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.sql.DataSource]: Factory method 'dataSource' threw exception; nested exception is java.lang.IllegalStateException: Mapped port can only be obtained after the container is started Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.sql.DataSource]: Factory method 'dataSource' threw exception; nested exception is java.lang.IllegalStateException: Mapped port can only be obtained after the container is started Caused by: java.lang.IllegalStateException: Mapped port can only be obtained after the container is started Here is my SpringBootTest:
@RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = {IntegrationDataService.class, TestApplication.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class SpringBootTestControllerTesterIT { @Autowired private MyController myController; @LocalServerPort private int port; @Autowired private TestRestTemplate restTemplate; @Test public void testRestControllerHello() { String url = "http://localhost:" + port + "/mycontroller/hello"; ResponseEntity<String> result = restTemplate.getForEntity(url, String.class); assertEquals(result.getStatusCode(), HttpStatus.OK); assertEquals(result.getBody(), "hello"); } } Here is my spring boot application referenced from the test:
@SpringBootApplication public class TestApplication { public static void main(String[] args) { SpringApplication.run(TestApplication.class, args); } } Here is the IntegrationDataService class which is intended to startup the container and provide the sessionfactory/datasource for everything else
@Testcontainers @TestInstance(TestInstance.Lifecycle.PER_CLASS) @EnableTransactionManagement @Configuration public class IntegrationDataService { @Container public static PostgreSQLContainer postgreSQLContainer = (PostgreSQLContainer) new PostgreSQLContainer("postgres:9.6") .withDatabaseName("test") .withUsername("sa") .withPassword("sa") .withInitScript("db/postgresql/schema.sql"); @Bean public Properties hibernateProperties() { Properties hibernateProp = new Properties(); hibernateProp.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect"); hibernateProp.put("hibernate.format_sql", true); hibernateProp.put("hibernate.use_sql_comments", true); // hibernateProp.put("hibernate.show_sql", true); hibernateProp.put("hibernate.max_fetch_depth", 3); hibernateProp.put("hibernate.jdbc.batch_size", 10); hibernateProp.put("hibernate.jdbc.fetch_size", 50); hibernateProp.put("hibernate.id.new_generator_mappings", false); // hibernateProp.put("hibernate.hbm2ddl.auto", "create-drop"); // hibernateProp.put("hibernate.jdbc.lob.non_contextual_creation", true); return hibernateProp; } @Bean public SessionFactory sessionFactory() throws IOException { LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean(); sessionFactoryBean.setDataSource(dataSource()); sessionFactoryBean.setHibernateProperties(hibernateProperties()); sessionFactoryBean.setPackagesToScan("com.myproject.model.entities"); sessionFactoryBean.afterPropertiesSet(); return sessionFactoryBean.getObject(); } @Bean public PlatformTransactionManager transactionManager() throws IOException { return new HibernateTransactionManager(sessionFactory()); } @Bean public DataSource dataSource() { BasicDataSource dataSource = new BasicDataSource(); dataSource.setDriverClassName(postgreSQLContainer.getDriverClassName()); dataSource.setUrl(postgreSQLContainer.getJdbcUrl()); dataSource.setUsername(postgreSQLContainer.getUsername()); dataSource.setPassword(postgreSQLContainer.getPassword()); return dataSource; } } The error occurs on requesting the datasource bean from the sessionFactory from one of the Dao classes before the container starts up.
What the heck am I doing wrong?
Thanks!!!