The ClickHouseContainer class provides the primary API for creating and managing ClickHouse database containers with JDBC connectivity. It extends JdbcDatabaseContainer and provides ClickHouse-specific configuration options.
Core Capabilities:
Key Methods:
ClickHouseContainer(String dockerImageName), ClickHouseContainer(DockerImageName dockerImageName)getJdbcUrl(), getDriverClassName(), getUsername(), getPassword(), getDatabaseName(), getTestQueryString()withUsername(), withPassword(), withDatabaseName(), withUrlParam(), withInitScript(), withInitScripts(), withStartupTimeoutSeconds(), withConnectTimeoutSeconds(), withReuse(), withEnv()start(), stop(), getMappedPort(), getHost(), getLivenessCheckPortNumbers()Default Behaviors:
com.clickhouse.jdbc.Driver first, then com.clickhouse.jdbc.ClickHouseDriver)Threading Model:
start() and stop() are blocking and should be called from a single threadLifecycle:
start() before usestart() blocks until container is healthystart() returnsstop() or use try-with-resourcesExceptions:
IllegalArgumentException: Invalid parameters (null/empty image name, null/empty username/database, invalid timeout)IllegalStateException: Methods called before start() or after stop(), multiple start() callsContainerLaunchException: Container fails to start (Docker issues, image pull failures, health check timeouts, script failures)TimeoutException: Startup timeout exceededClassNotFoundException: No JDBC driver found on classpathEdge Cases:
latest (not recommended)start() time, not constructionIllegalArgumentExceptionwithUrlParam() calls with same name: last value winsContainerLaunchException during start()testcontainers.reuse.enable=true in propertieswithEnv() throws IllegalArgumentExceptionwithEnv() sets variable to empty stringIllegalArgumentExceptionCreates a new ClickHouse container instance with the specified Docker image.
/**
* Create a ClickHouse container with a Docker image name string
* @param dockerImageName Docker image name (e.g., "clickhouse/clickhouse-server:24.12-alpine")
* @throws IllegalArgumentException if dockerImageName is null or empty
*/
public ClickHouseContainer(String dockerImageName);
/**
* Create a ClickHouse container with a DockerImageName object
* @param dockerImageName DockerImageName instance
* @throws IllegalArgumentException if dockerImageName is null
*/
public ClickHouseContainer(DockerImageName dockerImageName);Usage Examples:
import org.testcontainers.clickhouse.ClickHouseContainer;
import org.testcontainers.utility.DockerImageName;
// Using string image name
ClickHouseContainer container1 = new ClickHouseContainer("clickhouse/clickhouse-server:24.12-alpine");
// Using DockerImageName
DockerImageName imageName = DockerImageName.parse("clickhouse/clickhouse-server:24.12-alpine");
ClickHouseContainer container2 = new ClickHouseContainer(imageName);
// Must call start() to launch the container
container1.start();Edge Cases:
latest (not recommended for tests)start() time, not construction timeContainerLaunchException during start()IllegalArgumentException immediatelyGet JDBC connection details for the running container. All methods throw IllegalStateException if called before start().
/**
* Get the JDBC URL for connecting to the ClickHouse database
* Format: jdbc:clickhouse://host:port/database
* @return JDBC URL string
* @throws IllegalStateException if container is not started
*/
public String getJdbcUrl();
/**
* Get the JDBC driver class name
* Automatically detects and returns the appropriate driver based on classpath availability
* Priority: com.clickhouse.jdbc.Driver (new) > com.clickhouse.jdbc.ClickHouseDriver (legacy)
* @return Driver class name
* @throws IllegalStateException if container is not started
* @throws ClassNotFoundException if no JDBC driver is found on classpath
*/
public String getDriverClassName();
/**
* Get the configured username
* @return Username for database authentication (default: "test")
* @throws IllegalStateException if container is not started
*/
public String getUsername();
/**
* Get the configured password
* @return Password for database authentication (default: "test")
* @throws IllegalStateException if container is not started
*/
public String getPassword();
/**
* Get the configured database name
* @return Database name (default: "default")
* @throws IllegalStateException if container is not started
*/
public String getDatabaseName();
/**
* Get the test query string used for health checks
* @return Test query string ("SELECT 1")
* @throws IllegalStateException if container is not started
*/
public String getTestQueryString();Usage Examples:
import org.testcontainers.clickhouse.ClickHouseContainer;
import java.sql.Connection;
import java.sql.DriverManager;
try (ClickHouseContainer clickhouse = new ClickHouseContainer("clickhouse/clickhouse-server:24.12-alpine")) {
clickhouse.start();
// Get connection information
String jdbcUrl = clickhouse.getJdbcUrl();
// Returns: "jdbc:clickhouse://localhost:32768/default" (port varies)
String username = clickhouse.getUsername(); // Returns: "test"
String password = clickhouse.getPassword(); // Returns: "test"
String databaseName = clickhouse.getDatabaseName(); // Returns: "default"
String driverClass = clickhouse.getDriverClassName(); // Returns driver class name
// Create JDBC connection
try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password)) {
// Execute queries...
}
}Error Handling:
// Wrong: calling before start()
ClickHouseContainer container = new ClickHouseContainer("clickhouse/clickhouse-server:24.12-alpine");
String url = container.getJdbcUrl(); // Throws IllegalStateException
// Correct: start first
container.start();
String url = container.getJdbcUrl(); // OKEdge Cases:
IllegalStateException if called before start()getDriverClassName() throws ClassNotFoundException if no driver is on classpathjdbc:clickhouse://host:port/databasegetMappedPort(8123))Configure custom database credentials using fluent builder methods. Methods can be called in any order and are chainable.
/**
* Set custom username for database authentication
* @param username Username to use (cannot be null or empty)
* @return Self reference for method chaining
* @throws IllegalArgumentException if username is null or empty
*/
public ClickHouseContainer withUsername(String username);
/**
* Set custom password for database authentication
* @param password Password to use (cannot be null)
* @return Self reference for method chaining
* @throws IllegalArgumentException if password is null
*/
public ClickHouseContainer withPassword(String password);
/**
* Set custom database name
* @param databaseName Database name to use (cannot be null or empty)
* @return Self reference for method chaining
* @throws IllegalArgumentException if databaseName is null or empty
*/
public ClickHouseContainer withDatabaseName(String databaseName);Usage Examples:
import org.testcontainers.clickhouse.ClickHouseContainer;
// Configure custom credentials
try (ClickHouseContainer clickhouse = new ClickHouseContainer("clickhouse/clickhouse-server:24.12-alpine")
.withUsername("myuser")
.withPassword("mypassword")
.withDatabaseName("mydb")) {
clickhouse.start();
String jdbcUrl = clickhouse.getJdbcUrl();
// Returns: "jdbc:clickhouse://localhost:32768/mydb"
String username = clickhouse.getUsername(); // Returns: "myuser"
String password = clickhouse.getPassword(); // Returns: "mypassword"
String database = clickhouse.getDatabaseName(); // Returns: "mydb"
}Edge Cases:
IllegalArgumentExceptionIllegalArgumentExceptionAdd custom URL parameters to the JDBC connection string, useful for ClickHouse session settings and driver configuration.
/**
* Add a URL parameter to the JDBC connection string
* Parameters are appended to the JDBC URL as query parameters
* @param paramName Parameter name (use "clickhouse_setting_" prefix for session settings)
* @param paramValue Parameter value (will be URL-encoded)
* @return Self reference for method chaining
* @throws IllegalArgumentException if paramName or paramValue is null
*/
public ClickHouseContainer withUrlParam(String paramName, String paramValue);Usage Examples:
import org.testcontainers.clickhouse.ClickHouseContainer;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
// Configure ClickHouse session settings via URL parameters
try (ClickHouseContainer clickhouse = new ClickHouseContainer("clickhouse/clickhouse-server:24.12-alpine")
.withUrlParam("clickhouse_setting_max_result_rows", "1000")
.withUrlParam("clickhouse_setting_connect_timeout", "30")
.withUrlParam("custom_param", "value")) {
clickhouse.start();
String jdbcUrl = clickhouse.getJdbcUrl();
// Returns: "jdbc:clickhouse://localhost:32768/default?clickhouse_setting_max_result_rows=1000&clickhouse_setting_connect_timeout=30&custom_param=value"
try (Connection conn = DriverManager.getConnection(jdbcUrl, clickhouse.getUsername(), clickhouse.getPassword());
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT value FROM system.settings WHERE name='max_result_rows'")) {
rs.next();
System.out.println("max_result_rows: " + rs.getInt(1)); // Prints: 1000
}
}Common ClickHouse Settings:
clickhouse_setting_max_result_rows: Maximum rows in result setclickhouse_setting_max_execution_time: Query execution timeout in secondsclickhouse_setting_connect_timeout: Connection timeout in secondsclickhouse_setting_send_timeout: Send timeout in secondsclickhouse_setting_receive_timeout: Receive timeout in secondsEdge Cases:
withUrlParam with same name: last value winsIllegalArgumentExceptionclickhouse_setting_* prefix is required for ClickHouse session settingsExecute SQL scripts when the container starts, useful for setting up test schemas, tables, and initial data. Scripts are executed in order after the container is healthy but before start() returns.
/**
* Set a single initialization script to execute on container startup
* Replaces any previously set scripts
* Script path is resolved from classpath (e.g., "init.sql" in src/test/resources)
* @param initScriptPath Path to SQL script file (classpath resource)
* @return Self reference for method chaining
* @throws IllegalArgumentException if initScriptPath is null or empty
*/
public ClickHouseContainer withInitScript(String initScriptPath);
/**
* Set multiple initialization scripts to execute on container startup in order
* Replaces any previously set scripts
* @param initScriptPaths Paths to SQL script files (classpath resources)
* @return Self reference for method chaining
* @throws IllegalArgumentException if initScriptPaths is null or contains null/empty paths
*/
public ClickHouseContainer withInitScripts(String... initScriptPaths);
/**
* Set multiple initialization scripts from an iterable collection
* Replaces any previously set scripts
* @param initScriptPaths Iterable of paths to SQL script files
* @return Self reference for method chaining
* @throws IllegalArgumentException if initScriptPaths is null or contains null/empty paths
*/
public ClickHouseContainer withInitScripts(Iterable<String> initScriptPaths);Usage Examples:
import org.testcontainers.clickhouse.ClickHouseContainer;
import java.util.Arrays;
// Single initialization script
try (ClickHouseContainer clickhouse = new ClickHouseContainer("clickhouse/clickhouse-server:24.12-alpine")
.withInitScript("init.sql")) {
clickhouse.start();
// init.sql is executed before container is ready
}
// Multiple initialization scripts (executed in order)
try (ClickHouseContainer clickhouse = new ClickHouseContainer("clickhouse/clickhouse-server:24.12-alpine")
.withInitScripts("schema.sql", "data.sql", "indexes.sql")) {
clickhouse.start();
// Scripts executed in order: schema.sql, then data.sql, then indexes.sql
}
// From a collection
Iterable<String> scripts = Arrays.asList("init1.sql", "init2.sql");
try (ClickHouseContainer clickhouse = new ClickHouseContainer("clickhouse/clickhouse-server:24.12-alpine")
.withInitScripts(scripts)) {
clickhouse.start();
}Script Execution Details:
start() to throw ContainerLaunchExceptionstart() returnssrc/test/resources)Edge Cases:
ContainerLaunchException during start()ContainerLaunchExceptionwithConnectTimeoutSeconds())start()Configure startup and connection timeout values for the container. Timeouts are in seconds.
/**
* Set startup timeout including image pull time
* Includes time to pull image, create container, start container, and pass health check
* @param startupTimeoutSeconds Timeout in seconds (default: 120, minimum: 1)
* @return Self reference for method chaining
* @throws IllegalArgumentException if timeout is less than 1
*/
public ClickHouseContainer withStartupTimeoutSeconds(int startupTimeoutSeconds);
/**
* Set timeout for establishing initial database connection
* Used for health checks and initialization script execution
* @param connectTimeoutSeconds Timeout in seconds (default: 120, minimum: 1)
* @return Self reference for method chaining
* @throws IllegalArgumentException if timeout is less than 1
*/
public ClickHouseContainer withConnectTimeoutSeconds(int connectTimeoutSeconds);Usage Examples:
import org.testcontainers.clickhouse.ClickHouseContainer;
// Increase timeouts for slow environments
try (ClickHouseContainer clickhouse = new ClickHouseContainer("clickhouse/clickhouse-server:24.12-alpine")
.withStartupTimeoutSeconds(300) // 5 minutes for startup
.withConnectTimeoutSeconds(180)) { // 3 minutes for connection
clickhouse.start();
}
// Decrease timeouts for faster failure detection
try (ClickHouseContainer clickhouse = new ClickHouseContainer("clickhouse/clickhouse-server:24.12-alpine")
.withStartupTimeoutSeconds(30)) { // Fail fast if container doesn't start quickly
clickhouse.start();
}Timeout Behavior:
Edge Cases:
IllegalArgumentExceptionManage container lifecycle including starting, stopping, and getting port mappings. Lifecycle methods are not thread-safe.
/**
* Start the container
* Pulls the image if not present, creates the container, starts it, and waits until ready
* Blocks until container is healthy or timeout occurs
* @throws ContainerLaunchException if container fails to start
* @throws TimeoutException if startup timeout is exceeded
* @throws IllegalStateException if container is already started
*/
public void start();
/**
* Stop the container
* Stops and removes the container
* Safe to call multiple times (idempotent)
* @throws IllegalStateException if container was never started
*/
public void stop();
/**
* Get the mapped port for a container port
* Returns the host port that maps to the container port
* @param originalPort Original container port (8123 for HTTP, 9000 for native)
* @return Host port that maps to the container port
* @throws IllegalStateException if container is not started
* @throws IllegalArgumentException if originalPort is not exposed
*/
public Integer getMappedPort(int originalPort);
/**
* Get the container host
* Typically "localhost" but may vary in Docker networking configurations
* @return Host address
* @throws IllegalStateException if container is not started
*/
public String getHost();
/**
* Get ports used for liveness checks
* Returns set containing the HTTP port (8123)
* @return Set containing the HTTP port
* @throws IllegalStateException if container is not started
*/
public Set<Integer> getLivenessCheckPortNumbers();Usage Examples:
import org.testcontainers.clickhouse.ClickHouseContainer;
try (ClickHouseContainer clickhouse = new ClickHouseContainer("clickhouse/clickhouse-server:24.12-alpine")) {
// Start the container
clickhouse.start();
// Get mapped ports (8123 = HTTP port, 9000 = native port)
Integer httpPort = clickhouse.getMappedPort(8123);
// Returns: e.g., 32768 (dynamically assigned host port)
Integer nativePort = clickhouse.getMappedPort(9000);
// Returns: e.g., 32769
String host = clickhouse.getHost(); // Returns: "localhost"
// Manually construct connection URL if needed
String customUrl = "jdbc:clickhouse://" + host + ":" + httpPort + "/default";
// Stop is called automatically by try-with-resources
}Lifecycle States:
start() called, container is being created/startedError Handling:
// Multiple start() calls
container.start();
container.start(); // Throws IllegalStateException
// Calling methods before start()
Integer port = container.getMappedPort(8123); // Throws IllegalStateException
// Invalid port
Integer port = container.getMappedPort(9999); // Throws IllegalArgumentExceptionEdge Cases:
start() throws IllegalStateException if already startedstop() is idempotent (safe to call multiple times)stop() throws IllegalStateException if never startedIllegalStateException if called before start()getMappedPort() throws IllegalArgumentException for non-exposed portsEnable container reuse across test runs to improve performance. Requires testcontainers.reuse.enable=true in ~/.testcontainers.properties.
/**
* Enable or disable container reuse
* When enabled, container will be reused across test runs if configuration matches
* Configuration matching includes: image, credentials, database name, init scripts
* @param reuse True to enable reuse, false to disable
* @return Self reference for method chaining
*/
public ClickHouseContainer withReuse(boolean reuse);Usage Examples:
import org.testcontainers.clickhouse.ClickHouseContainer;
// Enable container reuse for faster test execution
try (ClickHouseContainer clickhouse = new ClickHouseContainer("clickhouse/clickhouse-server:24.12-alpine")
.withReuse(true)) {
clickhouse.start();
// Container will be reused if a matching container already exists
}Reuse Behavior:
testcontainers.reuse.enable=true in ~/.testcontainers.propertiesEdge Cases:
Set custom environment variables for the container. Environment variables are set before container starts.
/**
* Set an environment variable in the container
* Environment variables are available to the ClickHouse process
* @param key Environment variable name (cannot be null)
* @param value Environment variable value (can be null, sets to empty string)
* @return Self reference for method chaining
* @throws IllegalArgumentException if key is null
*/
public ClickHouseContainer withEnv(String key, String value);Usage Examples:
import org.testcontainers.clickhouse.ClickHouseContainer;
// Set custom environment variables
try (ClickHouseContainer clickhouse = new ClickHouseContainer("clickhouse/clickhouse-server:24.12-alpine")
.withEnv("CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT", "1")
.withEnv("TZ", "UTC")
.withEnv("CLICKHOUSE_LOG_LEVEL", "trace")) {
clickhouse.start();
}Common Environment Variables:
CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: Enable access management (1 = enabled)TZ: Timezone (e.g., "UTC", "America/New_York")CLICKHOUSE_LOG_LEVEL: Logging level (trace, debug, information, warning, error)CLICKHOUSE_USER_FILES_PATH: Path to user configuration filesEdge Cases:
IllegalArgumentExceptionCLICKHOUSE_USER, CLICKHOUSE_PASSWORD)import org.testcontainers.clickhouse.ClickHouseContainer;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class ClickHouseTest {
public void testClickHouse() throws Exception {
// Create container with full configuration
try (ClickHouseContainer clickhouse = new ClickHouseContainer("clickhouse/clickhouse-server:24.12-alpine")
.withUsername("testuser")
.withPassword("testpass")
.withDatabaseName("testdb")
.withUrlParam("clickhouse_setting_max_execution_time", "60")
.withInitScript("schema.sql")
.withStartupTimeoutSeconds(180)
.withReuse(true)
.withEnv("TZ", "UTC")) {
// Start container
clickhouse.start();
// Get connection details
String jdbcUrl = clickhouse.getJdbcUrl();
String username = clickhouse.getUsername();
String password = clickhouse.getPassword();
// Connect and execute queries
try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password)) {
// Create table
try (PreparedStatement stmt = conn.prepareStatement(
"CREATE TABLE IF NOT EXISTS users (id UInt32, name String) ENGINE = MergeTree() ORDER BY id")) {
stmt.execute();
}
// Insert data
try (PreparedStatement stmt = conn.prepareStatement(
"INSERT INTO users (id, name) VALUES (?, ?)")) {
stmt.setInt(1, 1);
stmt.setString(2, "Alice");
stmt.execute();
}
// Query data
try (PreparedStatement stmt = conn.prepareStatement("SELECT * FROM users WHERE id = ?");
ResultSet rs = stmt.executeQuery()) {
stmt.setInt(1, 1);
if (rs.next()) {
System.out.println("User: " + rs.getString("name"));
}
}
} catch (SQLException e) {
System.err.println("Database error: " + e.getMessage());
throw e;
}
} catch (ContainerLaunchException e) {
System.err.println("Container failed to start: " + e.getMessage());
throw e;
}
}
}ClickHouseContainer extends JdbcDatabaseContainer, which provides additional methods:
getJdbcUrl(): Returns JDBC URL (overridden by ClickHouseContainer)getDriverClassName(): Returns driver class name (overridden by ClickHouseContainer)getTestQueryString(): Returns test query (overridden by ClickHouseContainer)getDatabaseName(): Returns database name (overridden by ClickHouseContainer)getUsername(): Returns username (overridden by ClickHouseContainer)getPassword(): Returns password (overridden by ClickHouseContainer)waitingFor(WaitStrategy): Set custom wait strategywithLogConsumer(Consumer<OutputFrame>): Add log consumerwithImagePullPolicy(PullPolicy): Set image pull policywithNetwork(Network): Set Docker networkwithNetworkMode(String): Set network modewithNetworkAliases(String...): Add network aliaseswithExposedPorts(Integer...): Expose additional portswithCreateContainerCmdModifier(Consumer<CreateContainerCmd>): Modify container creation commandwithCommand(String...): Override container commandwithWorkingDirectory(String): Set working directorywithCopyFileToContainer(Transferable, String): Copy files to containerwithCopyToContainer(Transferable, String): Copy files to containerexecInContainer(String...): Execute commands in containergetContainerId(): Get container IDgetContainerInfo(): Get container infogetDockerImageName(): Get Docker image nameisRunning(): Check if container is runningisCreated(): Check if container is createdisHealthy(): Check if container is healthyAll inherited methods follow the same error handling patterns: throw IllegalStateException if called before start(), throw IllegalArgumentException for invalid parameters.