如何Docker Compose进行集成测试

Docker Compose + Testcontainers 构建一键式集成测试环境实战指南 集成测试是验证软件各组件协同工作的关键环节,其核心在于确保测试环境与生产环境的一致性。传统手动搭建环境的方式存在配置繁琐、环境漂移等问题。Docker 技术通过容器化实现了环境的一致性封装与隔离,而 Docker Compose 则能以声明式的方式编排多服务依赖。Testcontainers 作为测试库,进一步实现了以编程方式管理这些容器的生命周期,将环境准备与销毁自动化。这种技术组合为持续集成/持续部署(CI/CD)流水线提供了可靠基石,能显著提升开发效率和测试可靠性。本文聚焦于 Docker Compo 阅读详情

集成测试通常是一项困难的活动,特别是在涉及到分布式系统时。即便正在构建单体应用,也可能需要启动数据库,来进行集成测试。这种事情在早期很容易做到,但随着代码库的增加,难度将呈指数级增长。值得庆幸的是, Docker Compose 使我们能够在运行 Docker 的任何环境中,进行集成测试。


开始

假设从一个单体体制开始,拥有一个服务和一个数据库。你可以像 1999 年那样,从源代码构建应用服务和数据库;或使用 brew install 解决所有依赖关系。但最终你的系统看起来是这样的:

待测试端点是 /create,它做的全部事情是在数据库中存储一些数据。看起来非常简单。因此,可以编写如下 Bash 脚本 - CURL 端点;然后查询数据库(退出码 0 代表成功;退出码 1 代表失败)。该脚本很简单,但最重要的是它有效。

但是有很多隐藏的依赖项:

  • 必须安装和运行数据库
  • 必须安装单体应用框架
  • 必须运行单体应用
  • 需要 PATH 中有 CURL 的操作系统
  • 根据测试,数据库中的任何数据都可能导致测试结果不准确。

假设在 Bash 脚本中添加一行,重置数据。


mysql --user="$user" --password="$password" --database="$database" \
  --execute="TRUNCATE table table_name"
curl http://localhost:8000/create
COUNT = `mysql --user="$user" --password="$password" --database="$database"\
  --execute="SELECT COUNT(*) FROM table_name;"`
if [[ $COUNT -ne 1 ]]; then
  exit 1
fi

这样做可以消除最后一个隐藏依赖项(数据库中存在数据),但也带来非常严重的副作用,因为本地开发数据库与测试数据库共享。因此,每次运行集成测试,都会丢失全部开发数据😭。这似乎显而易见,但实际上这种体制仍然存在。然而不一定非要这样做。从此处开始,我将通过一个构建在 Docker Compose 上的示例,解决上面列出的所有问题。在本例中,将使用 Node 作为应用程序框架,使用 RethinkDB 作为数据库,但是你也可以选择其它技术栈。


制定策略

我们从 Martin Fowler 的微服务测试手册中学习集成测试。我们将在被测试的系统外部启动一个容器,使容器运行一些测试,然后检查测试容器的 run 命令的退出代码。

为清晰起见,下面列出文件结构,因为该项目中有多个 Dockerfile


integration-test/
  Dockerfile
  index.js
  package.json
  test.sh
  docker-compose.yml
index.js
package.json
Dockerfile

接下来走查集成测试的每个组件。


临时数据库

有时丢弃所有数据是好事,在运行测试时,丢弃数据是必要的。使用 Docker compose 实现这一点非常容易,只需启动数据库,无需挂载数据卷。这意味着当销毁容器时,数据也随之消失。还意味着如果不销毁容器,那么可以进入容器内部,对数据库运行查询,进行调试。下面是一个示例 Docker Compose 文件,它只启动一个临时数据库(RethinkDB)。

integration-test/docker-compose.yml


version: '2'

services:
  rethinkdb:
    image: rethinkdb
    expose:
      - "28015"

记住这个概念,因为我们很快就会用到它。


应用程序容器

下一步是容器化将要测试的应用程序。需要构建/运行应用程序,连接数据库,以及暴露用于测试的端口。

Dockerfile

FROM mhart/alpine-node
WORKDIR /service
COPY package.json .
RUN npm install
COPY index.js .
integration-test/docker-compose.yml



version: '2'

services:
  my-service:
    build: ..
    command: npm start
    links:
      - rethinkdb
    ports:
      - "8080:8080"
  rethinkdb:
    image: rethinkdb
    expose:
      - "28015"

此时,可以使用 docker-compose up 检查服务,以及访问http://localhost:8080 (只要你拥有服务器,并且线路已连接)。


集成测试容器

现在,我们已拥有数据库和应用程序,接下来构建测试容器。该容器需要向 my-service 上的 /create 端点发送 POST 请求,并且检查数据库中的变更。为实现这一点,这里使用 taperequest-promise 检查端点。

integration-test/index.js

import test from 'tape';
import requestPromise from 'request-promise';

const before = test;
const after = test;

const beforeEach = () => {/*test setup*/};

const afterEach = () => {/*test cleanup*/};

before('before', (t) => {/*one time setup*/});

test('POST /create', (t) => {
  beforeEach()
    .then(() => (
      requestPromise({
        method: 'POST',
        // yes! we can use the service name in the docker-compose.yml file
        uri: 'http://my-service:8080/create',
        body: {
          thing: 'this thing',
        },
      })
    ))
    .then((response) => {
      // inspect the response
      t.equal(response.statusCode, 200, 'statusCode: 200');
    })
    .then(() => (
      // inspect the database
      rethinkdb.table('table_name')
        .filter({
          thing: 'this thing',
        })
        .count()
        .run(connection)
        .then((value) => {
          t.equal(value, 1, 'have data');
        })
    ))
    .catch((error) => t.fail(error))
    .then(() => afterEach())
    .then(() => t.end());
});

after('after', (t) => {/*one time setup*/});

测试 Dockerfile 看起来与应用程序 Dockerfile 相同。

integration-test/Dockerfile


FROM mhart/alpine-node
WORKDIR /integration
COPY package.json .
RUN npm install
COPY index.js .

现在,将测试应用程序添加到 docker-compose.yml 文件。

integration-test/docker-compose.yml


version: '2'

services:
  integration-tester:
    build: .
    links:
      - my-service
  my-service:
    build: ..
    command: npm start
    links:
      - rethinkdb
    ports:
      - "8080:8080"
  rethinkdb:
    image: rethinkdb
    expose:
      - "28015"

这里是很酷的部分,当运行 docker-compose up 时,将发生如下事情

  • 构建 my-serviceintegration-tester 容器
  • 连接及运行 my-serviceintegration-testerrethinkdb 容器
  • integration-tester 运行所有测试,直到停止
  • integration-tester 停止后,docker-compose 关闭所有容器

这正是需要在 CI 中运行的集成测试。到目前为止,我们尚未检查 integration-tester 容器的退出码,接下来马上讲述。


将所有东西结合起来

在所有自动化工作就绪后,我们需要将所有东西结合起来,并且在测试完成后,执行清理工作。为此,我们使用 docker wait 阻塞脚本,获取测试的退出码。我们使用该退出码输出消息(通过/失败),并且使用相同的退出码退出主脚本。这很有用因为大多数(并非全部)CI 环境使用退出码确定测试成功与否。我们还将获取测试容器的日志,并且将它们打印出来,以便在测试失败时提供上下文。下面是一个(极其冗长的)脚本,它完成我们在本地或 CI 中运行集成测试所需的一切。

integration-test/test.sh


# define some colors to use for output
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'
# kill and remove any running containers
cleanup () {
  docker-compose -p ci kill
  docker-compose -p ci rm -f --all
}
# catch unexpected failures, do cleanup and output an error message
trap 'cleanup ; printf "${RED}Tests Failed For Unexpected Reasons${NC}\n"'\
  HUP INT QUIT PIPE TERM
# build and run the composed services
docker-compose -p ci build && docker-compose -p ci up -d
if [ $? -ne 0 ] ; then
  printf "${RED}Docker Compose Failed${NC}\n"
  exit -1
fi
# wait for the test service to complete and grab the exit code
TEST_EXIT_CODE=`docker wait ci_integration-tester_1`
# output the logs for the test (for clarity)
docker logs ci_integration-tester_1
# inspect the output of the test and display respective message
if [ -z ${TEST_EXIT_CODE+x} ] || [ "$TEST_EXIT_CODE" -ne 0 ] ; then
  printf "${RED}Tests Failed${NC} - Exit Code: $TEST_EXIT_CODE\n"
else
  printf "${GREEN}Tests Passed${NC}\n"
fi
# call the cleanup fuction
cleanup
# exit the script with the same code as the test service code
exit $TEST_EXIT_CODE

示例

如欲获得完整示例,请查看 auth-service。想要看到它的实际效果,你需要做:

git clone https://github.com/hharnisc/auth-service.git
cd auth-service
npm test

对于更复杂的示例(多层微服务),请查看login-service login-service

git clone https://github.com/hharnisc/login-service.git
cd login-service
npm test

总结

这种方式在实践中效果很好,我已经使用该方式为一些微服务执行集成测试。每当我在 CI 中遇到失败时,同样的 Bug 肯定可以在本地复现。我遇到的最大问题是,因为应用程序没有完全启动,而导致的测试失败。为解决该问题,我在应用程序上实现一个 /health API 端点,并且在测试的 before 块内部添加重试。自从修复该问题后,再没遇到其它古怪的问题,并且一直使用该方式在 CI 中运行集成测试。这真的很有用,并且已经捕获一些可能在部署过程中出现的实际 Bug,我希望你也能发现它有用。


Read Also

Python集成测试革命:用Testcontainers+Docker Compose构建可复现的多服务环境 在微服务与分布式系统开发中,集成测试是确保软件质量的关键环节,其核心挑战在于如何快速构建一个与生产环境一致、可复现且易于管理的测试环境。传统方案如维护独立测试服务器或手动脚本管理Docker容器,常面临环境不一致、配置复杂和难以集成CI/CD等问题。通过将基础设施即代码(IaC)理念引入测试领域,Testcontainers等工具实现了“测试即代码”,允许开发者以编程方式定义和管理测试依赖。结合Docker Compose对多服务拓扑的描述能力,可以一键拉起包含数据库、缓存、消息队列等组件的完整环境。这种技 阅读详情

相关推荐

docker 安装rocketmq

前言 首先我们是使用Docker进行搭建环境的,所以我们先要在自己机器上的安装Docker,具体的安装过程以及对于Docker的介绍官方文档里面说的很清楚了https://docs.docker.com/get-started/。 我们要搭建RocketMQ服务器,那么我们就要知道大概搭建RocketMQ服务器需要部署哪些东西。对于RocketMQ有一个架构图,如下所示。而图中所示的Producer(生产者)和Consumer(消费者)无需我们搭建,因为那是作为一个服务器进行启动的。nameserver就是

一种感觉的博客 440

【持续集成CI/持续部署CD】六、Docker Compose构建CI全流程

从 Jenkins 的登录界面提示可以知道,默认密码路径为/var/jenkins_home/secrets/initialAdminPassword,这里显示的事 Docker 容器内部的路径,实际对应我们上面服务器设置的路径为/data/docker/ci/jenkins/home/secrets/initialAdminPassword ,我们打开这个文件并输入密码就可以进入 Jenkins 管理界面。插件(用于多个微服务时,选择需要构建的微服务)、系统管理–>凭据–>系统–>全局凭据。

全栈程序猿的专栏 1741

docker-compose详解

一、Docker Compose1、前言2、官方介绍1、Compose 中有两个重要的概念2、三步骤3、ComposeDocker官方的开源项目,需要安装!4、Compose:重要的概念二、docker compose 安装1、下载2、bash命令补全3、卸载(没有安装不需要执行)4、授权5、检测版本三、docker compose使⽤1、相关概念2、场景 3.docker-compose模板4、启动5、docker-compose 模板⽂件1、build2、command3、container_name

@峰的博客 2万+

docker和服务器集成_与docker和testcontainers进行集成测试

docker和服务器集成We, as good developers, create unit tests for every piece of code we write, so we can be confident to iterate on the code. Unit tests are fast, reliable and relatively easy to write and ma...

weixin_26720549的博客 859

Dockertest 极速搭建集成测试环境神器

1 推荐背景在开发应用程序时,经常需要与数据库系统交互的服务,如,各种数据库,以及 minio,Kafka,Redis 等服务组件,没错Dockertest 基本都支持主流数据库和服务组件。对这些服务进行集成测试是很麻烦的,因为模拟数据库/数据库抽象层是很费劲的一件事。对模式进行细微的更改意味着至少重写部分(如果不是全部)模拟;数据库抽象层中的API 变化也是如此。为了避...

Go中国 973

Docker Compose和SQL集成测试的终极指南

更新9/5/2020 (Updated 9/5/2020) In the previous versions of this article, I’ve stated that theseed container doesn’t have to wait for thedb container. That turned out not to be the case. The article ha...

weixin_26717681的博客 284

推荐文章:pytest-docker-compose——集成测试的得力助手

推荐文章:pytest-docker-compose——集成测试的得力助手 pytest-docker-composeSpin up Docker containers during your integration tests automatically!项目地址:https://gitcode.com/gh_mirrors/py/pytest-docker-compose 项目介绍 在快速...

gitblog_00049的博客 362

yowsup集成测试环境终极指南:Docker Compose模拟生产环境

想要构建稳定可靠的即时通讯应用?yowsup集成测试环境是你的最佳选择!😊 yowsup是一个强大的Python库,专门用于开发能与即时通讯用户通信的应用程序。通过Docker Compose搭建的集成测试环境,开发者可以模拟真实的生产环境,确保应用在各种场景下都能稳定运行。 ## 🚀 为什么需要集成测试环境? 在开发即时通讯相关应用时,直接连接到真实服务器进行测试存在诸多限制和风险。集成

gitblog_00599的博客 346

llmfit 集成测试体系指南:从 Docker Compose 验证到 test_*.sh 脚本编写规范

llmfit 是一个面向“数百模型与提供方、一条命令找出能在你的硬件上运行的模型”的工具链,其 [tests/](https://link.gitcode.com/i/f902738d7afefebdd4d0804ab4fa028b) 目录承载了项目层面的集成、端到端与基础设施验证测试。本文以该目录的测试文档为骨架,结合 [test_docker_compose.sh](https://link.

gitblog_00649的博客 424

测试Spark流:与Docker Compose集成测试

在本系列的第一篇文章中,我们了解了如何使用Spark Testing Base对 Spark Streaming操作进行单元测试。 在这里,我们将看到如何使用Docker Compose进行集成测试。 什么是集成测试 我们之前看到了有关单元和集成测试的讨论。 再次,由于我们要保持重点,我们将使用具有以下特征的集成测试定义: 网络集成:我们的代码应调用网络以与第三方依赖项集成。 然后...

danpob13624的博客 205

Syft集成测试数据:使用Docker Compose模拟依赖服务

在软件开发过程中,集成测试是确保各个组件协同工作的关键环节。对于Syft这样的CLI工具和库,其功能依赖于多种外部服务和环境。本文将介绍如何使用Docker Compose模拟这些依赖服务,以便进行有效的集成测试。 ## Docker Compose配置文件 首先,我们需要创建一个Docker Compose配置文件来定义所需的服务。在Syft项目中,可能涉及到的依赖服务包括数据库、消息队列等。...

gitblog_00695的博客 825

OpenTelemetry Collector 集成测试环境搭建:Docker Compose全栈方案

你是否还在为分布式追踪系统的本地验证头疼?是否在多组件联调时被环境配置搞得焦头烂额?本文将带你用Docker Compose快速搭建OpenTelemetry Collector的全栈测试环境,实现"一键启动、零配置验证"的开发体验。 读完本文你将获得: - 3分钟快速部署Collector+观测后端的完整链路 - 可视化界面实时验证追踪数据流转 - 可复用的配置模板适配不同测试场景 - 性能压...

gitblog_00542的博客 580

MLOps Zoomcamp 最佳实践篇:pytest 单元测试docker-compose 集成测试、Terraform IaC 与 GitHub Actions CI/CD 的完整落地指南

本文基于 MLOps Zoomcamp 课程仓库第 6 周 Best Practices 模块([06-best-practices/README.md](https://link.gitcode.com/i/71b7bb04441bb605865360600e779b48))整理展开。该模块分为两大部分:Part A 覆盖 pytest 单元测试docker-compose 集成测试、Loca

gitblog_01042的博客 1013

**pytest-docker-compose 快速入门与实战指南**

pytest-docker-compose 快速入门与实战指南 1. 项目介绍 pytest-docker-compose 是一个专为 pytest 设计的插件,它旨在简化集成测试过程中 Docker Compose 的管理。通过这个工具,你可以利用 Docker 容器环境进行自动化测试。它自动处理容器的构建、启动和销毁流程,只需提供 docker-compose.yml 文件即可。该插件支持 P...

gitblog_00344的博客 404

Vector 集成测试框架完全指南:基于 vdev 与 Docker Compose 的 integration test 实践

本文以 Vector 仓库中 [tests/integration/README.md](https://link.gitcode.com/i/f4f7e369fa570c39376ad7cb2b89f82c) 为骨架,系统讲解 Vector 集成测试的组织方式与运行方法。你将掌握 `vdev` 工具的核心子命令(`show`/`start`/`test`/`stop`)、`compose.yam

gitblog_01003的博客 225

docker-compose启动微型集群获取集成测试代码覆盖率

docker-compose启动微型集群,jenkins流水线执行测试脚本并获取集成测试代码覆盖率

帅小缙的大脑风暴❤ 753

探索Dockest:简化多容器Docker应用的集成测试之旅

探索Dockest:简化多容器Docker应用的集成测试之旅 在当今快节奏的软件开发环境中,高效的集成测试对于确保应用程序质量至关重要。今天,我们将一同深入了解一款名为Dockest的强大工具,它专为解决多容器Docker环境下的单元测试评估难题而设计。 项目介绍 Dockest,正如其名,是一款旨在减轻多容器Docker应用进行集成测试负担的利器。通过一个直观的接口,它管理着服务的生命周期,自动...

gitblog_00835的博客 927
上一篇: 如何创建一个有效的数字编码表格?
下一篇: 深入了解现代 SAST 工具​​
why811
博客等级 码龄17年 10粉丝 75原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值