作者:韩山杰 Databend Cloud 研发工程师 hantmac (Jeremy) · GitHub
Testcontainers 是一个开源库,用于提供一次性的、轻量级的数据库实例、消息代理、网络浏览器,或者任何可以在 Docker 容器中运行的服务。
其核心特点是:
- 一次性:测试完成后可以直接丢弃
- 轻量级:启动快速,资源占用少
- 基于 Docker:利用容器技术实现隔离
主要可以用到以下场景:
- 数据库测试:MySQL、PostgreSQL、MongoDB 等
- 消息队列测试:RabbitMQ、Kafka 等
- 浏览器自动化测试
- 任何可容器化的服务测试
使用 TestContainers 构建测试用例可以避免测试环境污染,保证测试环境一致性,简化测试配置的同时并提高测试可靠性。
这个工具特别适合需要依赖外部服务的测试场景,能够快速创建隔离的测试环境。
Support Databend for Testcontainers
Databend 团队分别在 testcontainer-java, testcontainers-go, testcontainers-rs 的 PR 中为三种主流编程语言完整地支持了 Databend 数据源,这意味着开发者可以在这些语言的项目中轻松集成 Databend 的测试环境。
准备工作
- 确保操作环境中已安装 Docker。
- 已安装 Java、Go 以及 Rust 的开发环境
Java
依赖配置
我们首先新建一个 Java Demo 项目,这里以 Maven 为例,在 pom.xml 中添加 Databend 的 testcontainers 和 databend-jdbc 的依赖:
<dependencies><dependency><groupId>org.testcontainers</groupId><artifactId>databend</artifactId><version>1.20.4</version><scope>test</scope></dependency><dependency><groupId>com.databend</groupId><artifactId>databend-jdbc</artifactId><version>0.2.8</version></dependency></dependencies>
如果是 Gradle 可以使用:
testImplementation "org.testcontainers:databend:1.20.4"
新建测试类
我们新建一个 TestContainerDatabend
的测试类并为其创建构造方法:
public class TestContainerDatabend {private final DatabendContainer dockerContainer;public TestContainerDatabend() {dockerContainer = new DatabendContainer("datafuselabs/databend:v1.2.615");dockerContainer.withUsername("databend").withPassword("databend").withUrlParam("ssl", "false");dockerContainer.start();}}
可以看到在代码中我们指定了 datafuselabs/databend:v1.2.615
作为 Databend 启动的 docker image(选择其他版本的 image 可以访问:https://hub.docker.com/r/datafuselabs/databend),并为本次启动的 Databend 设置了用户名、密码,随后我们立即启动容器服务。 我们使用该服务完成本次测试用例:
......@Testpublic void testSimple() {try (Connection connection = DriverManager.getConnection(getJdbcUrl())) {DatabendStatement statement = (DatabendStatement) connection.createStatement();statement.execute("SELECT 1");ResultSet r = statement.getResultSet();while (r.next()) {int resultSetInt = r.getInt(1);System.out.println(resultSetInt);assert resultSetInt == 1;}} catch (Exception e) {throw new RuntimeException("Failed to execute statement: ", e);}}public String getJdbcUrl() {return format("jdbc:databend://%s:%s@%s:%s/",dockerContainer.getUsername(),dockerContainer.getPassword(),dockerContainer.getHost(),dockerContainer.getMappedPort(8000));}
运行测试的同时我们可以在系统看到 testcontainers 为我们启动了一个 Databend 容器服务:
当测试结束后会立即销毁该容器释放资源。
除了 Databend 之外,Testcontainers 支持市面上绝大多数的数据库、消息队列,可以轻松构建依赖这些资源的测试集。
完整的项目代码可以参考 testcontainers-databend。
Go
同样地,在 Golang 项目中如果需要用到 Databend 服务,也可以使用 testcontainers-go
。
package mainimport ("context""database/sql""testing"_ "github.com/datafuselabs/databend-go""github.com/stretchr/testify/require""github.com/testcontainers/testcontainers-go""github.com/testcontainers/testcontainers-go/modules/databend"
)func TestDatabend(t *testing.T) {ctx := context.Background()ctr, err := databend.Run(ctx, "datafuselabs/databend:v1.2.615")testcontainers.CleanupContainer(t, ctr)require.NoError(t, err)// perform assertionsconnectionString, err := ctr.ConnectionString(ctx, "sslmode=disable")require.NoError(t, err)mustConnectionString := ctr.MustConnectionString(ctx, "sslmode=disable")require.Equal(t, connectionString, mustConnectionString)db, err := sql.Open("databend", connectionString)require.NoError(t, err)defer db.Close()err = db.Ping()require.NoError(t, err)_, err = db.Exec("CREATE TABLE IF NOT EXISTS a_table ( \n" +" `col_1` VARCHAR(128) NOT NULL, \n" +" `col_2` VARCHAR(128) NOT NULL \n" +")")require.NoError(t, err)
}
Rust
Databend 原本就是使用 Rust 写的,当然可以在 Rust 项目中使用 testcontainer-rs
来快速启动一个 Databend 容器服务。
#[cfg(test)]
mod tests {use databend_driver::Client;use crate::{databend::Databend as DatabendImage, testcontainers::runners::AsyncRunner};#[tokio::test]async fn test_databend() {let databend = DatabendImage::default().start().await.unwrap();let http_port = databend.get_host_port_ipv4(8000).await.unwrap();// "databend://user:password@localhost:8000/default?sslmode=disablelet dsn = format!("databend://databend:databend@localhost:{}/default?sslmode=disable",http_port);let client = Client::new(dsn.to_string());let conn = client.get_conn().await.unwrap();let row = conn.query_row("select 'hello'").await.unwrap();assert!(row.is_some());let row = row.unwrap();let (val,): (String,) = row.try_into().unwrap();assert_eq!(val, "hello");let conn2 = conn.clone();let row = conn2.query_row("select 'world'").await.unwrap();assert!(row.is_some());let row = row.unwrap();let (val,): (String,) = row.try_into().unwrap();assert_eq!(val, "world");}
}
结论
对于现代软件开发而言,可靠的测试框架和工具链是保证代码质量的重要基石。随着 Databend 对 Testcontainers 的多语言支持的完善,开发者能够更加便捷地进行数据库相关的集成测试,从而提升整体的开发效率和代码质量。
无论是使用 Java、Go 还是 Rust,Testcontainers 都能为 Databend 开发者的测试工作提供可靠的支持。我们期待看到更多开发者在实际项目中运用这一强大的测试工具,构建更加稳健的应用系统。
关于 Databend
Databend 是一款开源、弹性、低成本,基于对象存储也可以做实时分析的新式数仓。期待您的关注,一起探索云原生数仓解决方案,打造新一代开源 Data Cloud。
👨💻 Databend Cloud:databend.cn
📖 Databend 文档:docs.databend.cn/
💻 Wechat:Databend
✨ GitHub:github.com/databendlab...