Dmytro Chasovskyi
Dmytro Chasovskyi

Reputation: 3621

How to use testcontainers in existing application?

CONTEXT:

I have an existing Camel application. In order to test it with Spring Boot tools, it is wrapped into the Spring Boot framework and all tests run against this Spring Boot app. Important: This code is used in production, so I am not allowed to change implementation and rewrite tests altogether. To test the app in a prod-like environment I use testcontainers and Microsoft SQL Server in Docker, it is an additional functional tests module.

What I am trying to do is to spin up testcontainers and update DataSource, so it will point to SQL Server endpoint. I bumped into a never-ending series of problems. What am I doing wrong?

PROBLEM:

My SpringBootTestApplication looks:

@SpringBootApplication
public class SpringBootTestApplication {

    @Bean(name = "myDataSource")
    public DataSource dataSource() throws ClassNotFoundException {
        SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
        dataSource.setDriverClass(Class.forName("org.apache.derby.jdbc.EmbeddedDriver").asSubclass(Driver.class));
        dataSource.setUrl("jdbc:derby:memory:testdb;create=true");
        dataSource.setUsername("sa");
        dataSource.setPassword("");

        Resource initSchema = new ClassPathResource("db/schema.sql");
        ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator(initSchema);
        databasePopulator.setIgnoreFailedDrops(true);
        DatabasePopulatorUtils.execute(databasePopulator, dataSource);
        return dataSource;
    }


    public static void main(String[] args) {
        SpringApplication.run(SpringBootTestApplication.class, args);
    }
}

My test looks this way:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = SpringBootTestApplication.class)
@TestPropertySource("classpath:application-test.properties")
public class LargeDatabaseRetrieverTest {

    @Rule
    public MSSQLServerContainer mssqlServerContainer = (MSSQLServerContainer) new MSSQLServerContainer()
            .withInitScript("db/test-data-mssql.sql")
            .withExposedPorts(1433);

    @Autowired
    @Qualifier("myDataSource")
    private DataSource dataSource;

    @Before
    public void setUp() throws Exception {
        mssqlServerContainer.start();

        DataSource mssqlDataSource = configureDataSource();
        AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory();
        factory.autowireBean(mssqlDataSource);
    }

    @After
    public void tearDown() throws Exception {
        mssqlServerContainer.stop();
    }

    private DataSource configureDataSource() {
        BasicDataSource basicDataSource = new BasicDataSource();
        basicDataSource.setDriverClassName(mssqlServerContainer.getDriverClassName());
        basicDataSource.setUrl(mssqlServerContainer.getJdbcUrl());
        basicDataSource.setUsername(mssqlServerContainer.getUsername());
        basicDataSource.setPassword(mssqlServerContainer.getPassword());
        return basicDataSource;
    }

    @Test
    public void test() {
        // Use DataSource in here
    }

}

I am trying to dynamically load DataSource into a test, so I will test against MS SQL Server, not against default in-memory configuration.

The issue is that I don't know the configuration of MS SQL Server Docker container until it started and I cannot dynamically inject my own DataSource implementation.

LIST OF ATTEMPTED SOLUTIONS:

None of the above solutions work. It seems that I do something wrong and got lost between three birches. What am I doing wrong?

Upvotes: 0

Views: 3285

Answers (1)

bsideup
bsideup

Reputation: 3063

Have you checked Spring Boot's docs on how to use it with Testcontainers? Or Testcontainers' Spring Boot example?

There is also a workshop.

Last but not least, if you only need an SQL database, you can use the JDBC URL support.

Upvotes: 1

Related Questions