作者:韩山杰 Databend Cloud 研发工程师 https://github.com/hantmac
Testcontainers 是一个开源库,用于提供一次性的、轻量级的数据库实例、消息代理、网络浏览器,或者任何可以在 Docker 容器中运行的服务。
其核心特点是:
一次性:测试完成后可以直接丢弃
轻量级:启动快速,资源占用少
基于 Docker:利用容器技术实现隔离
主要可以用到以下场景:
使用 TestContainers 构建测试用例可以避免测试环境污染,保证测试环境一致性,简化测试配置的同时并提高测试可靠性。
这个工具特别适合需要依赖外部服务的测试场景,能够快速创建隔离的测试环境。
Support Databend for Testcontainers
Databend 团队分别在 testcontainer-java, testcontainers-go, testcontainers-rs 的 PR 中为三种主流编程语言完整地支持了 Databend 数据源,这意味着开发者可以在这些语言的项目中轻松集成 Databend 的测试环境。
准备工作
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 设置了用户名、密码,随后我们立即启动容器服务。我们使用该服务完成本次测试用例:
......
@Test
public 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 main
import (
"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 assertions
connectionString, 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=disable
let 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...
评论