integration-testingtestcontainers-junit5

Connect my Oraclecontainer to an external database (not localhost) for integration tests Java/ Springboot


I want to change my integration tests (use oracle 19c database) by using testcontainers.

So installed docker in local and run the Docker Desktop.

after i used the image gvenzl/oracle-xe:18.4.0-slim and i run it locally.

After in my code (java & spring boot), i have the external database connexion declared in application-integrationTests.properties

app.datasource.url=jdbc:oracle:thin:@//IT-host:1529/DEV_APP
app.datasource.driverClassName=oracle.jdbc.OracleDriver
app.datasource.username=DEMO
app.datasource.password=DEMO

and in my ServerConfigIntegrationTest, i had this code before

public DataSource specificDatasource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
return dataSource;
    }

So, i modified this configuration by

@Testcontainers
public class ServerConfigIntegrationTest{
... code 

@Container
    private final OracleContainer oracleContainer = new OracleContainer("gvenzl/oracle-xe:18.4.0-slim")
            .withReuse(true)
            .withPassword("DEMO")
            .withUsername("DEMO")
            .withDatabaseName("DEV_APP")
            .withLogConsumer(new Slf4jLogConsumer(LOGGER));
    @Bean
    @Primary
    public DataSource specificDatasource() {
        oracleContainer.start();
        LOGGER.info("The JDBC URL of the container is: "+ oracleContainer.getJdbcUrl());        
        dataSource.setDriverClassName(oracleContainer.getDriverClassName());        
        dataSource.setUrl(oracleContainer.getJdbcUrl());
        dataSource.setUsername(oracleContainer.getUsername());
        dataSource.setPassword(oracleContainer.getPassword());
        return dataSource;
        }

when i'm logging the jdbcUrl, i have localhost as server and the bad port.

How can i do to connect my container to the database (with a specific host "IT-host") ? Can you help me ?


Solution

  • When you're using Testcontainers an ephemeral Docker container with the database is created and its lifecycle managed by your tests via Testcontainers.

    When you specify this:

    @Container
        private final OracleContainer oracleContainer = new OracleContainer("gvenzl/oracle-xe:18.4.0-slim")
                .withReuse(true)
                .withPassword("DEMO")
                .withUsername("DEMO")
                .withDatabaseName("DEV_APP")
                .withLogConsumer(new Slf4jLogConsumer(LOGGER));
    

    Testcontainers JUnit integration will control the lifecycle of the Docker containers with the database. There are more details here you can configure it to create a new DB for every test or test class, etc. There are more options for manual control too.

    The container will map the internal ports necessary for DB access to random high ports on your machine, which is why you see localhost & a high port in the jdbcUrl.

    The proper way to make you Spring Boot application to use the database in that container is to use DynamicPropertySource: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/context/DynamicPropertySource.html

    Which you'd do like this:

    @DynamicPropertySource
         static void redisProperties(DynamicPropertyRegistry registry) {
             registry.add("spring.datasource.url", oracleContainer::getJdbcUrl);
             registry.add("spring.datasource.username", oracleContainer::getUsername);
             registry.add("spring.datasource.password", oracleContainer::getPassword);
         }
    

    DynamicPropertySource will configure your Spring Boot app to use the containerized DB for the tests. You don't need the integration tests configuration or running an existing database at all in that setup.

    You cannot use Testcontainers tests against an already existing instance of the database running.