Testcontainers module for Oracle XE database - provides lightweight, throwaway instances of Oracle XE database for integration testing
Reactive database connectivity using R2DBC for non-blocking database operations. Provides factory methods and configuration options for reactive programming patterns with Oracle databases.
Wraps Oracle XE containers to provide R2DBC connectivity with automatic connection factory configuration and lifecycle management delegation.
public class OracleR2DBCDatabaseContainer implements R2DBCDatabaseContainer {
public OracleR2DBCDatabaseContainer(OracleContainer container);
public static ConnectionFactoryOptions getOptions(OracleContainer container);
public ConnectionFactoryOptions configure(ConnectionFactoryOptions options);
}Parameters:
container (OracleContainer): Underlying Oracle container instanceReturns:
ConnectionFactoryOptions: Configured R2DBC connection optionsOracleR2DBCDatabaseContainer: R2DBC wrapper instanceUsage Example:
// Create Oracle container
OracleContainer oracleContainer = new OracleContainer("gvenzl/oracle-xe:18.4.0-slim")
.withDatabaseName("r2dbc_test")
.withUsername("r2dbcuser")
.withPassword("r2dbcpass");
// Wrap with R2DBC container
OracleR2DBCDatabaseContainer r2dbcContainer =
new OracleR2DBCDatabaseContainer(oracleContainer);
// Start container (delegated to underlying Oracle container)
r2dbcContainer.start();
// Get connection factory options
ConnectionFactoryOptions options = OracleR2DBCDatabaseContainer.getOptions(oracleContainer);Automatically configures R2DBC connection factory options with Oracle-specific driver settings, host/port mapping, and authentication credentials.
public ConnectionFactoryOptions configure(ConnectionFactoryOptions options);Parameters:
options (ConnectionFactoryOptions): Base connection factory optionsReturns:
ConnectionFactoryOptions: Configured options with Oracle container detailsUsage Example:
OracleContainer container = new OracleContainer("gvenzl/oracle-xe:18.4.0-slim");
container.start();
OracleR2DBCDatabaseContainer r2dbcContainer = new OracleR2DBCDatabaseContainer(container);
// Configure connection factory options
ConnectionFactoryOptions baseOptions = ConnectionFactoryOptions.builder()
.option(ConnectionFactoryOptions.DRIVER, "oracle")
.build();
ConnectionFactoryOptions configuredOptions = r2dbcContainer.configure(baseOptions);
// Result includes:
// - HOST: container.getHost()
// - PORT: container.getMappedPort(OracleContainer.ORACLE_PORT)
// - DATABASE: container.getDatabaseName()
// - USER: container.getUsername()
// - PASSWORD: container.getPassword()Service Provider Interface (SPI) implementation for automatic R2DBC container discovery and creation with connection factory metadata support.
public class OracleR2DBCDatabaseContainerProvider implements R2DBCDatabaseContainerProvider {
static final String DRIVER = "oracle";
public boolean supports(ConnectionFactoryOptions options);
public R2DBCDatabaseContainer createContainer(ConnectionFactoryOptions options);
public ConnectionFactoryMetadata getMetadata(ConnectionFactoryOptions options);
}Parameters:
options (ConnectionFactoryOptions): R2DBC connection factory optionsReturns:
boolean: Whether provider supports the driver typeR2DBCDatabaseContainer: New R2DBC container instanceConnectionFactoryMetadata: Connection metadata with defaultsUsage Example:
// Create connection factory options
ConnectionFactoryOptions options = ConnectionFactoryOptions.builder()
.option(ConnectionFactoryOptions.DRIVER, "oracle")
.option(ConnectionFactoryOptions.DATABASE, "testdb")
.option(IMAGE_TAG_OPTION, "18.4.0-slim")
.option(REUSABLE_OPTION, true)
.build();
// Use provider
OracleR2DBCDatabaseContainerProvider provider = new OracleR2DBCDatabaseContainerProvider();
// Check support
boolean supports = provider.supports(options); // true for oracle driver
// Create container
R2DBCDatabaseContainer r2dbcContainer = provider.createContainer(options);
// Get metadata with defaults
ConnectionFactoryMetadata metadata = provider.getMetadata(options);
// Automatically adds default USER and PASSWORD if not specifiedR2DBC containers delegate lifecycle operations to the underlying Oracle container while implementing the Startable interface for seamless integration.
// Delegated methods from Startable interface
public void start();
public void stop();
public boolean isRunning();Usage Example:
OracleContainer oracleContainer = new OracleContainer("gvenzl/oracle-xe:18.4.0-slim");
OracleR2DBCDatabaseContainer r2dbcContainer = new OracleR2DBCDatabaseContainer(oracleContainer);
// Lifecycle operations (delegated to Oracle container)
r2dbcContainer.start();
boolean running = r2dbcContainer.isRunning();
r2dbcContainer.stop();
// Container state is managed by underlying Oracle container
assertEquals(oracleContainer.isRunning(), r2dbcContainer.isRunning());@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Testcontainers
class ReactiveOracleTest {
@Container
static OracleContainer oracle = new OracleContainer("gvenzl/oracle-xe:18.4.0-slim")
.withDatabaseName("reactive_test");
@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
ConnectionFactoryOptions options = OracleR2DBCDatabaseContainer.getOptions(oracle);
registry.add("spring.r2dbc.url", () ->
"r2dbc:oracle://" + options.getRequiredValue(ConnectionFactoryOptions.HOST) +
":" + options.getRequiredValue(ConnectionFactoryOptions.PORT) +
"/" + options.getRequiredValue(ConnectionFactoryOptions.DATABASE)
);
registry.add("spring.r2dbc.username", oracle::getUsername);
registry.add("spring.r2dbc.password", oracle::getPassword);
}
@Autowired
private R2dbcEntityTemplate template;
@Test
void testReactiveConnection() {
StepVerifier.create(
template.getDatabaseClient()
.sql("SELECT 1 FROM DUAL")
.map(row -> row.get(0, Integer.class))
.one()
)
.expectNext(1)
.verifyComplete();
}
}@Test
void testDirectR2DBCUsage() {
OracleContainer container = new OracleContainer("gvenzl/oracle-xe:18.4.0-slim");
container.start();
// Get connection factory options
ConnectionFactoryOptions options = OracleR2DBCDatabaseContainer.getOptions(container);
// Create connection factory
ConnectionFactory connectionFactory = ConnectionFactories.get(options);
// Use reactive connection
Mono.from(connectionFactory.create())
.flatMap(connection ->
Mono.from(connection.createStatement("SELECT SYSDATE FROM DUAL")
.execute())
.flatMap(result ->
Mono.from(result.map((row, metadata) ->
row.get(0, LocalDateTime.class))))
.doFinally(signal -> connection.close())
)
.as(StepVerifier::create)
.expectNextMatches(timestamp -> timestamp != null)
.verifyComplete();
}@Repository
public class ReactiveUserRepository {
private final R2dbcEntityTemplate template;
public ReactiveUserRepository(R2dbcEntityTemplate template) {
this.template = template;
}
public Flux<User> findAllUsers() {
return template.select(User.class)
.from("users")
.all();
}
public Mono<User> saveUser(User user) {
return template.insert(User.class)
.using(user);
}
public Mono<User> findUserById(Long id) {
return template.select(User.class)
.from("users")
.matching(query(where("id").is(id)))
.one();
}
}
@Test
void testReactiveRepository() {
// Container setup
OracleContainer container = new OracleContainer("gvenzl/oracle-xe:18.4.0-slim")
.withInitScript("classpath:schema.sql");
container.start();
// Configure R2DBC
ConnectionFactoryOptions options = OracleR2DBCDatabaseContainer.getOptions(container);
ConnectionFactory connectionFactory = ConnectionFactories.get(options);
R2dbcEntityTemplate template = new R2dbcEntityTemplate(connectionFactory);
ReactiveUserRepository repository = new ReactiveUserRepository(template);
// Test reactive operations
User newUser = new User("Alice", "alice@example.com");
StepVerifier.create(
repository.saveUser(newUser)
.then(repository.findAllUsers().collectList())
)
.expectNextMatches(users -> users.size() == 1)
.verifyComplete();
}The R2DBC Oracle connection factory supports the following standard options:
// Standard R2DBC options
ConnectionFactoryOptions.DRIVER = "oracle"
ConnectionFactoryOptions.HOST = container.getHost()
ConnectionFactoryOptions.PORT = container.getMappedPort(OracleContainer.ORACLE_PORT)
ConnectionFactoryOptions.DATABASE = container.getDatabaseName()
ConnectionFactoryOptions.USER = container.getUsername()
ConnectionFactoryOptions.PASSWORD = container.getPassword()
// Testcontainers-specific options
IMAGE_TAG_OPTION = "18.4.0-slim" // Docker image tag
REUSABLE_OPTION = true // Container reuse flagWhen connection factory options don't specify user credentials, the R2DBC provider automatically applies default values:
This ensures seamless integration even when credentials are not explicitly configured in the connection factory options.
Install with Tessl CLI
npx tessl i tessl/maven-org-testcontainers--oracle-xe