如何用Bazel与Docker Compose运行客户端SDK集成测试?
Bazel下SDK集成测试的Docker方案选型与实践
一、sh_test + docker-compose 完全可行
用sh_test触发docker-compose拉起服务端和测试容器的方案完全能跑通,核心逻辑很直接:
- 写个shell脚本,搞定镜像拉取/构建、启动容器栈、等服务就绪、跑测试、最后清资源这一套流程
- 把脚本挂到Bazel的
sh_test规则里,同时把SDK测试二进制、docker-compose.yml设为依赖,确保Bazel能把这些文件丢到测试沙箱里
但要注意几个关键细节:
- 强制清资源:不管测试过没过,都要执行
docker-compose down -v --remove-orphans,不然残留的容器会搞砸下一次测试 - 服务就绪检查:别上来就跑测试,用
curl或nc轮询服务端的健康检查接口,确认服务起来了再执行测试 - 依赖路径:Bazel的测试沙箱路径是临时的,脚本里要注意用相对路径或者
$TEST_SRCDIR环境变量找依赖文件
示例sh_test规则:
sh_test( name = "sdk_integration_test", srcs = ["run_integration_test.sh"], data = [ ":gtest_binary", "docker-compose.yml", ], tags = ["docker"], # 标记需要Docker环境,方便CI过滤 )
示例脚本片段(run_integration_test.sh):
#!/bin/bash set -euo pipefail # 切换到测试沙箱的工作目录 cd "$TEST_SRCDIR/your_workspace_name/sdk" # 启动容器栈 docker-compose up -d # 等待服务端就绪,最多等30秒 count=0 until curl -s http://localhost:8080/health; do sleep 1 count=$((count+1)) if [ $count -gt 30 ]; then echo "服务端启动超时" exit 1 fi done # 执行测试(如果测试二进制在容器里,就用docker exec;如果在宿主机,直接跑) docker exec sdk-test-container ./gtest_binary # 不管成功失败,退出前清资源 trap "docker-compose down -v --remove-orphans" EXIT INT TERM
二、更优方案:用Bazel官方的rules_docker
比起sh_test + docker-compose,官方的rules_docker和Bazel的构建体系深度集成,适合长期维护的项目,优势很明显:
- 一站式构建测试:不需要额外写
Dockerfile和docker-compose.yml,所有镜像定义、测试逻辑都在Starlark里统一管理 - 自动依赖同步:只要SDK或服务端代码变了,Bazel会自动重新构建镜像,不用手动同步版本
- 隔离性更好:用
container_test规则跑测试,容器之间的网络是隔离的,不会干扰宿主机或其他测试 - 缓存省时间:Bazel的增量构建会缓存镜像层,重复构建快很多
示例配置思路:
- 构建服务端镜像:
load("@io_bazel_rules_docker//container:container.bzl", "container_image") container_image( name = "server_image", base = "@ubuntu_latest//image", # 提前用docker_pull拉取基础镜像 cmd = ["/usr/bin/server"], files = [":server_binary"], # 依赖服务端二进制 )
- 构建测试镜像(包含SDK的gtest二进制):
container_image( name = "test_image", base = "@ubuntu_latest//image", cmd = ["./gtest_binary"], files = [":gtest_binary"], # 依赖SDK测试二进制 env = {"SERVER_ADDR": "server:8080"}, # 直接通过环境变量指定服务端地址,不用硬编码 )
- 用
container_test启动两个容器并跑测试:
load("@io_bazel_rules_docker//container:container.bzl", "container_test") container_test( name = "sdk_integration_test", images = { "server:latest": ":server_image", "test:latest": ":test_image", }, network = "bridge", # 让两个容器在同一网络里通信 test_image = "test:latest", # 指定跑测试的容器 timeout = "300s", )
三、选型建议
- 临时测试、小型项目:直接上
sh_test + docker-compose,不用学新规则,快得很 - 长期维护的大型项目:优先用
rules_docker,减少维护成本,测试更可靠,构建也更快
内容的提问来源于stack exchange,提问作者Howard Yu
相关产品推荐
相关产品推荐

