Testcontainers module for ClickHouse provides lightweight, throwaway instances of ClickHouse database containers for testing Java applications. It enables developers to create reproducible test environments with real ClickHouse databases, ensuring tests run in isolation with automatic container lifecycle management and proper cleanup.
Required Dependencies:
org.testcontainers:clickhouse (this package, version 1.21.4)org.testcontainers:testcontainers core package is required (provided transitively)Core Capabilities:
ClickHouseContainer - Main JDBC-based container implementation extending JdbcDatabaseContainerClickHouseProvider - Service provider enabling JDBC URL-based container instantiation (e.g., jdbc:tc:clickhouse://)ClickHouseR2DBCDatabaseContainer - R2DBC wrapper for reactive database connectivityClickHouseR2DBCDatabaseContainerProvider - R2DBC provider for URL-based instantiationKey Interfaces and Classes:
ClickHouseContainer - Main container class: new ClickHouseContainer(String dockerImageName), start(), stop(), getJdbcUrl(), getDriverClassName(), getUsername(), getPassword(), getDatabaseName(), withUsername(), withPassword(), withDatabaseName(), withUrlParam(), withInitScript(), withInitScripts(), withStartupTimeoutSeconds(), withConnectTimeoutSeconds(), withReuse(), withEnv(), getMappedPort(), getHost()ClickHouseProvider - Service provider: supports(String databaseType), newInstance(), newInstance(String tag)ClickHouseR2DBCDatabaseContainer - R2DBC wrapper: new ClickHouseR2DBCDatabaseContainer(ClickHouseContainer), getOptions(ClickHouseContainer), configure(ConnectionFactoryOptions), start(), stop()ClickHouseR2DBCDatabaseContainerProvider - R2DBC provider: supports(ConnectionFactoryOptions), createContainer(ConnectionFactoryOptions), getMetadata(ConnectionFactoryOptions)Default Behaviors:
clickhouse/clickhouse-server:24.12-alpine (must be specified in constructor)testtestdefault8123 (database access and health checks, mapped to random host port)9000 (console access, mapped to random host port)com.clickhouse.jdbc.Driver > com.clickhouse.jdbc.ClickHouseDriver)jdbc:clickhouse://host:port/databaser2dbc:tc:clickhouse:///database?parametersjdbc:tc:clickhouse://host/database?parametersCLICKHOUSE_DB, CLICKHOUSE_USER, CLICKHOUSE_PASSWORD automatically setThreading Model:
start() and stop() methods are blocking and should be called from a single threadstart(), stop()) are blocking even for R2DBC wrappersLifecycle:
start() before use (blocking call)start() returnsstop() or use try-with-resources for automatic cleanupstart() returnsstart() to throw ContainerLaunchExceptiontestcontainers.reuse.enable=true in ~/.testcontainers.propertiesstart() on wrapper or wrapped container)Exceptions:
IllegalStateException: Thrown if container methods are called in wrong order (e.g., getJdbcUrl() before start())ContainerLaunchException: Thrown if container fails to start (Docker issues, image pull failures, health check timeouts, initialization script failures)TimeoutException: Thrown if startup timeout is exceededSQLException: Thrown by JDBC operations (connection failures, query errors)ClassNotFoundException: Thrown if no JDBC driver is found on classpath when getDriverClassName() is calledIllegalArgumentException: Thrown for invalid parameters (null/empty image name, null/empty username/database name, invalid timeout values, null parameter names/values)EvaluationException: Thrown by SpEL expression evaluation (if used in custom configurations)Edge Cases:
latest (not recommended for tests)start() time, not construction timeContainerLaunchException during start()IllegalArgumentExceptionIllegalArgumentException for required parameterswithUrlParam with same name: last value winsContainerLaunchException during start()ContainerLaunchExceptionwithConnectTimeoutSeconds())start() calls throw IllegalStateExceptionstart() throws IllegalStateExceptionIllegalArgumentExceptionwithEnv() throws IllegalArgumentExceptionwithEnv() sets environment variable to empty stringCLICKHOUSE_USER, CLICKHOUSE_PASSWORD)com.clickhouse.jdbc.Driver (new driver), falls back to com.clickhouse.jdbc.ClickHouseDriver (legacy driver)SQLException with descriptive messageContainerLaunchException during container startIllegalArgumentExceptionClassNotFoundException when creating connection factoryIllegalStateException when accessing port/hostIllegalArgumentException or use wrong providerwithStartupTimeoutSeconds())withNetwork() and withNetworkAliases() for multi-container testsstart() to return before connecting clients; container may need additional time to be fully readycom.clickhouse.jdbc.Driver) recommended for ClickHouse versions 20.7 and latercom.clickhouse.jdbc.ClickHouseDriver supported for backward compatibilityclickhouse_setting_* prefix required for ClickHouse session settingsTC_IMAGE_TAG, TC_REUSABLE, TC_INITSCRIPT are case-sensitiver2dbc:tc: prefixPackage Name: org.testcontainers:clickhouse
Package Type: maven
Language: Java
Installation:
Maven:
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>clickhouse</artifactId>
<version>1.21.4</version>
<scope>test</scope>
</dependency>Gradle:
testImplementation "org.testcontainers:clickhouse:1.21.4"Important: This module does not automatically include a ClickHouse JDBC driver. You must add one of the following drivers as a dependency:
<!-- New driver (recommended) -->
<dependency>
<groupId>com.clickhouse</groupId>
<artifactId>clickhouse-jdbc</artifactId>
<version>0.7.2</version>
<classifier>http</classifier>
<scope>test</scope>
</dependency>import org.testcontainers.clickhouse.ClickHouseContainer;
import org.testcontainers.utility.DockerImageName;For R2DBC support:
import org.testcontainers.clickhouse.ClickHouseR2DBCDatabaseContainer;
import io.r2dbc.spi.ConnectionFactoryOptions;import org.testcontainers.clickhouse.ClickHouseContainer;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
// Create and start a ClickHouse container
try (ClickHouseContainer clickhouse = new ClickHouseContainer("clickhouse/clickhouse-server:24.12-alpine")) {
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);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT 1")) {
rs.next();
System.out.println("Result: " + rs.getInt(1));
}
}The ClickHouse Testcontainers module is built around several key components:
JdbcDatabaseContainer, providing ClickHouse-specific configuration and automatic health checking via HTTP endpointjdbc:tc:clickhouse://)ClickHouseR2DBCDatabaseContainer and ClickHouseR2DBCDatabaseContainerProviderCore JDBC-based ClickHouse container with automatic configuration, lifecycle management, and health checking. Supports custom credentials, database names, initialization scripts, and URL parameters.
public class ClickHouseContainer extends JdbcDatabaseContainer<ClickHouseContainer> {
// Constructors
public ClickHouseContainer(String dockerImageName);
public ClickHouseContainer(DockerImageName dockerImageName);
// Connection information
public String getJdbcUrl();
public String getDriverClassName();
public String getUsername();
public String getPassword();
public String getDatabaseName();
public String getTestQueryString();
// Configuration methods
public ClickHouseContainer withUsername(String username);
public ClickHouseContainer withPassword(String password);
public ClickHouseContainer withDatabaseName(String databaseName);
public ClickHouseContainer withUrlParam(String paramName, String paramValue);
public ClickHouseContainer withInitScript(String initScriptPath);
public ClickHouseContainer withInitScripts(String... initScriptPaths);
public ClickHouseContainer withInitScripts(Iterable<String> initScriptPaths);
public ClickHouseContainer withStartupTimeoutSeconds(int startupTimeoutSeconds);
public ClickHouseContainer withConnectTimeoutSeconds(int connectTimeoutSeconds);
public ClickHouseContainer withReuse(boolean reuse);
public ClickHouseContainer withEnv(String key, String value);
// Lifecycle methods
public void start();
public void stop();
public Integer getMappedPort(int originalPort);
public String getHost();
public Set<Integer> getLivenessCheckPortNumbers();
}Service provider for creating ClickHouse containers directly from JDBC URLs, enabling seamless integration with JDBC connection pools and frameworks.
public class ClickHouseProvider extends JdbcDatabaseContainerProvider {
public boolean supports(String databaseType);
public JdbcDatabaseContainer<?> newInstance();
public JdbcDatabaseContainer<?> newInstance(String tag);
}Reactive database connectivity for ClickHouse containers, providing non-blocking database access through R2DBC. Supports both programmatic and URL-based instantiation patterns.
public class ClickHouseR2DBCDatabaseContainer implements R2DBCDatabaseContainer {
public ClickHouseR2DBCDatabaseContainer(ClickHouseContainer container);
public static ConnectionFactoryOptions getOptions(ClickHouseContainer container);
public void start();
public void stop();
public ConnectionFactoryOptions configure(ConnectionFactoryOptions options);
}
public class ClickHouseR2DBCDatabaseContainerProvider implements R2DBCDatabaseContainerProvider {
public boolean supports(ConnectionFactoryOptions options);
public R2DBCDatabaseContainer createContainer(ConnectionFactoryOptions options);
public ConnectionFactoryMetadata getMetadata(ConnectionFactoryOptions options);
}clickhouse/clickhouse-server24.12-alpinetesttestdefaultThe container exposes two ports:
The container automatically configures the following environment variables:
CLICKHOUSE_DB: Database name (default: "default")CLICKHOUSE_USER: Username (default: "test")CLICKHOUSE_PASSWORD: Password (default: "test")The module automatically detects and supports multiple ClickHouse JDBC drivers:
com.clickhouse.jdbc.Driver - Recommended for ClickHouse versions 20.7 and latercom.clickhouse.jdbc.ClickHouseDriver - Supported for backward compatibilityDriver selection is automatic based on classpath availability. The new driver is recommended for ClickHouse versions 20.7 and later.
Driver Detection Logic:
com.clickhouse.jdbc.Driver (new driver)com.clickhouse.jdbc.ClickHouseDriver (legacy driver)ClassNotFoundException if neither driver is foundAlways use try-with-resources to ensure proper cleanup:
try (ClickHouseContainer container = new ClickHouseContainer("clickhouse/clickhouse-server:24.12-alpine")) {
container.start();
// Use container...
} // Container automatically stoppedEnable container reuse to speed up test execution (containers persist across test runs):
try (ClickHouseContainer container = new ClickHouseContainer("clickhouse/clickhouse-server:24.12-alpine")
.withReuse(true)) {
container.start();
// Container will be reused if configuration matches
}Important: Container reuse requires testcontainers.reuse.enable=true in ~/.testcontainers.properties.
Multiple containers can run in parallel (each gets unique ports):
// Safe to run in parallel - each container gets unique ports
@Test
public void test1() {
try (ClickHouseContainer c1 = new ClickHouseContainer("clickhouse/clickhouse-server:24.12-alpine")) {
c1.start();
// Test 1...
}
}
@Test
public void test2() {
try (ClickHouseContainer c2 = new ClickHouseContainer("clickhouse/clickhouse-server:24.12-alpine")) {
c2.start();
// Test 2...
}
}Use initialization scripts for consistent test data:
try (ClickHouseContainer container = new ClickHouseContainer("clickhouse/clickhouse-server:24.12-alpine")
.withInitScripts("schema.sql", "test-data.sql")) {
container.start();
// Schema and data are already loaded
}ContainerLaunchException: Container failed to start
try {
container.start();
} catch (ContainerLaunchException e) {
// Handle: Docker not running, image pull failure, health check timeout
System.err.println("Container failed to start: " + e.getMessage());
}IllegalStateException: Method called in wrong order
// Wrong: calling getJdbcUrl() before start()
String url = container.getJdbcUrl(); // Throws IllegalStateException
// Correct: start first
container.start();
String url = container.getJdbcUrl(); // OKTimeoutException: Startup timeout exceeded
try (ClickHouseContainer container = new ClickHouseContainer("clickhouse/clickhouse-server:24.12-alpine")
.withStartupTimeoutSeconds(30)) {
container.start(); // May throw TimeoutException if container takes > 30s
} catch (TimeoutException e) {
// Increase timeout or check Docker performance
}If health check fails, container startup will timeout:
// Health check may fail if:
// 1. ClickHouse takes longer than expected to start
// 2. Port 8123 is not accessible
// 3. ClickHouse returns unexpected response
// Solution: Increase timeout
container.withStartupTimeoutSeconds(300); // 5 minuteswithStartupTimeoutSeconds() to fail fast on slow environmentsimport org.junit.jupiter.api.Test;
import org.testcontainers.clickhouse.ClickHouseContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
@Testcontainers
public class ClickHouseTest {
@Container
static ClickHouseContainer clickhouse = new ClickHouseContainer("clickhouse/clickhouse-server:24.12-alpine");
@Test
public void test() {
String jdbcUrl = clickhouse.getJdbcUrl();
// Use container...
}
}@SpringBootTest
@Testcontainers
public class SpringBootTest {
@Container
static ClickHouseContainer clickhouse = new ClickHouseContainer("clickhouse/clickhouse-server:24.12-alpine");
@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", clickhouse::getJdbcUrl);
registry.add("spring.datasource.username", clickhouse::getUsername);
registry.add("spring.datasource.password", clickhouse::getPassword);
}
}import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
try (ClickHouseContainer container = new ClickHouseContainer("clickhouse/clickhouse-server:24.12-alpine")) {
container.start();
HikariConfig config = new HikariConfig();
config.setJdbcUrl(container.getJdbcUrl());
config.setUsername(container.getUsername());
config.setPassword(container.getPassword());
try (HikariDataSource dataSource = new HikariDataSource(config)) {
// Use connection pool...
}
}