Testcontainers is a popular framework that lets you test applications against real, disposable containers. It helps ensure your tests run against realistic environments without requiring complex infrastructure setup.
In this article, we’ll use the GenericContainer class to implement an Oracle Database Free container for testing, experimentation, and POCs. Our implementation will use the testcontainers-nodejs SDK and the Oracle Database Free container image.
Implementing Testcontainers for Oracle Database Free
We’ll define a class for an Oracle Database Free container using the testcontainers-nodejs SDK. The provided GenericContainer class makes it easy to add our custom Oracle Database logic.
By default, the OracleDatabaseContainer class spins up the latest gvenzl/oracle-free image with a configurable username and password. After calling start(), apps can connect to the container database using the freepdb1 service:
import {GenericContainer, type StartedTestContainer, Wait} from "testcontainers";
import * as OracleDB from "oracledb";
import type {Connection} from "oracledb";
// Implements an Oracle Database Free container for Testcontainers.
// Run the sample using "npm run testcontainers-example"
export class OracleDatabaseContainer {
private container?: StartedTestContainer | undefined;
constructor(
private readonly image: string = "gvenzl/oracle-free:23.26.0-slim-faststart",
private readonly port: number = 1521,
private readonly username: string = "testuser",
private readonly password: string = "Welcome12345",
private readonly serviceName: string = "freepdb1"
) {}
public async start(): Promise<StartedTestContainer> {
this.container = await new GenericContainer(this.image)
.withExposedPorts(this.port)
.withEnvironment({
"ORACLE_RANDOM_PASSWORD": "y",
"APP_USER": this.username,
"APP_USER_PASSWORD": this.password
})
.withWaitStrategy(Wait.forLogMessage("DATABASE IS READY TO USE!"))
.start();
return this.container;
}
public getHost(): string {
if (!this.container) throw new Error("Container not started yet");
return this.container.getHost();
}
public getPort(): number {
if (!this.container) throw new Error("Container not started yet");
return this.container.getMappedPort(this.port);
}
public async getDatabaseConnection(): Promise<Connection> {
return OracleDB.getConnection({
user: this.username,
password: this.password,
connectionString: this.getConnectionString()
})
}
public getConnectionString(): string {
return `${this.getHost()}:${this.getPort()}/${this.serviceName}`;
}
public async stop(): Promise<void> {
if (this.container) {
await this.container.stop();
this.container = undefined;
}
}
}
Now that we have a container class, let’s verify it by writing a test.
A Sample Test
To verify the database container implementation, let’s write a sample test. Our sample test uses vitest to start a database container, get a new connection, and query the database version:
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
import {OracleDatabaseContainer} from "../../src/testcontainers/oracle_database_container.js";
describe("OracleDatabaseContainer", () => {
let db: OracleDatabaseContainer;
beforeAll(async () => {
db = new OracleDatabaseContainer();
await db.start();
}, 10 * 60 * 1000); // On a fresh image pull, it may take a moment to start. Otherwise, the container should start up in seconds.
afterAll(async () => {
await db.stop();
});
it("should connect and get the current database version", async () => {
let conn = await db.getDatabaseConnection();
const result = await conn.execute("select * from V$VERSION")
expect(result).not.toBeUndefined()
if (result.rows) {
for (const row of result.rows) {
console.log(row);
}
}
await conn.close();
});
});You can extend this test to add application logic – supply the database connection information to your app, and then test functionality against the container database!
In addition to this example, I also have sample code for a database container inheriting from GenericContainer: generic_oracle_database_container.ts
Run the Example Yourself
To run the example, download the Oracle Code Samples repository and navigate to the typescript directory. Install dependencies with npm (requires a new-ish version of node), and start the testcontainers example:
npm i
npm run testcontainers-exampleAfter the container starts, you should see information about the database version printed to the console.
[
'Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free'
]
Leave a Reply