05 集成测试:如何进行微服务的集成测试?

2023-10-30

上一课时,我讲解了微服务架构下的单元测试,它是一种白盒测试技术,目的是验证软件代码中的每个单元(方法或类等)是否符合预期。本节课我来讲解微服务架构下的集成测试。

集成测试的概念

说到集成测试,相信每个测试工程师并不陌生,它不是一个崭新的概念,通过维基百科定义可以知道它在传统软件测试中的含义。

Integration testing (sometimes called integration and testing, abbreviated I&T) is the phase in software testing in which individual software modules are combined and tested as a group. Integration testing is conducted to evaluate the compliance of a system or component with specified functional requirements.

即,集成测试(有时称为集成和测试,简称 I&T)是软件测试中的阶段,在该阶段中,将各个单独开发的软件模块组合在一起并进行整体测试,以便评估系统或组件是否符合指定的功能要求。

微服务架构下也需要集成测试,需要针对不同服务的不同方法之间的通信情况进行相关测试。 因为在对微服务进行单元测试时,单元测试用例只会验证被测单元的内部逻辑,并不验证其依赖的模块。即使对于服务 A 和服务 B 的单元测试分别通过,并不能说明服务 A 和服务 B 的交互是正常的。

对于微服务架构来说,集成测试通常关注于验证那些与外部组件(例如数据存储或其他微服务)通信的子系统或模块。 目标是验证这些子系统或模块是否可以正确地与外部组件进行通信,而不是测试外部组件是否正常工作。因此,微服务架构下的集成测试,应该验证要集成的子系统之间与外部组件之间的基本通信路径,包括正确路径和错误路径。

微服务架构下的集成测试

image (6).png

微服务结构图与集成测试边界

如上图所示,网关组件层(Gateways+Http Client+External Service)包含了访问外部服务的逻辑,通常包含一个 HTTP/S 的客户端,客户端会连接到系统中另一个微服务或外部服务。数据持久层(Date Mappers/ORM)用于连接外部数据存储。

即,微服务架构下的集成测试主要包括两部分:

  1. 网关组件层, 微服务的组件与外部服务的通信路径;

  2. 数据持久层, 数据库访问模块与外部数据库的交互。

这里请注意,因为需要测试微服务下子系统之间的通信和外部服务的通信是否正确,所以理想情况下不应该对外部组件使用测试替身(Test Double)。

下面我们逐一来看这两部分是如何进行集成测试的:

(1)网关组件层集成测试

image (7).png

假设有个登录服务,该服务需要知道当前时间,而时间是由一个外部的时间服务提供的。当向 /api/json/cet/now 发出 GET 请求时,状态码为 200,并返回如下完整的时间信息。

{ 
$id"1", 
currentDateTime"2020-07-29T02:11+02:00", 
utcOffset"02:00:00", 
isDayLightSavingsTimetrue, 
dayOfTheWeek"Wednesday", 
timeZoneName"Central Europe Standard Time", 
currentFileTime132404622740972830, 
ordinalDate"2020-211", 
serviceResponsenull, 
}

如果访问的 URL 错误,比如向 /api/json111/cet/now发出 GET 请求时,状态码为 404,返回如下错误提示。

您要找的资源已被删除、已更名或暂时不可用。

一般来说,集成测试会负责检验与外部服务的连接以及交互协议相关的问题,如 HTTP header 的缺失、SSL 处理的异常,或者请求/响应的不匹配。所有的错误处理逻辑都需要在测试中被覆盖,以确保所使用的服务和协议客户端在特殊情况下能够按预期进行响应。

(2)数据持久层集成测试

数据持久层的集成测试则要复杂一些,因为结果会被保存在存储系统上并被持久化,每次测试的执行都可能因为更改了数据而对后续测试的执行产生影响。这意味着,两次测试之间并非完全独立,因为它们操作了共同的数据。

绝大多数情况下,应该保证两次测试之间的外部因素也是相互独立的。因为这样的错误(测试数据的修改而导致的测试执行失败)出现后往往很难意识到,进而影响排查进度。

为了保障两次测试的独立性,持久层集成测试的常见步骤是:

  1. 在执行任意测试前,先回退数据库到一个已知且可预测的状态,这需要清理/回滚之前对数据库的修改;

  2. 通过插入对测试来说已知且预期中的数据来重建数据库;

  3. 进行相关的测试;

  4. 循环上述这个过程。

image (8).png

常见问题及解决策略

然而,有很多时候外部服务不可用(服务尚未开发完成、服务有 block 级别的缺陷未修复),或其异常行为(如外部组件的超时、响应变慢等)很难去验证。外部组件不能使用测试替身,外部服务又不可用或异常场景难构造,看似无解,实际上都是有替代方案的。

服务不可用

针对服务不可用的情况,微服务虚拟化技术可以完美解决这种问题,它是避免与其他服务通信时出现意外的必要工具,在具有大量依赖项的企业环境中工作的时候更是如此。它可以用于在测试阶段消除对第三方服务的依赖,测试应用程序在遇到延迟或其他网络问题时的行为。它通过创建代理服务实现对依赖服务的模拟,特别适合测试服务之间的通信。常见的工具有 Wiremock、Hoverfly、Mountebank 等。

以 Wiremock 为例,如下代码的效果是:当相对 URL 完全匹配 /api/json/cet/now 时,将返回状态 200,响应的主体类似于  /api/json/cet/now的返回值,Content-Type Header 的值为 text/plain。否则,当相对 URL 错误,比如访问 /api/json111/cet/now 时,则返回 404 的错误。

@Test 
public void exactUrlOnly() { 
    stubFor(get(urlEqualTo("/api/json/cet/now")) 
            .willReturn(aResponse() 
                .withHeader("Content-Type", "text/plain") 
                .withBody(equalToJson("{ 
                      $id: \"1\", 
                      currentDateTime: \"2020-07-29T02:11+02:00\", 
                      utcOffset: \"02:00:00\", 
                      isDayLightSavingsTime: true, 
                      dayOfTheWeek: \"Wednesday\", 
                      timeZoneName: \"Central Europe Standard Time\", 
                      currentFileTime: 132404622740972830, 
                      ordinalDate: \"2020-211\", 
                      serviceResponse: null, 
                      }")))); 
    assertThat(testClient.get("/api/json/cet/now").statusCode(), is(200)); 
    assertThat(testClient.get("/api/json111/cet/now").statusCode(), is(404)); 
}
服务超时&响应慢难构造

如果使用真实服务测试,服务超时或响应慢等情况需要特殊构造下,这时候借助各种工具会比较方便,比如常见的软件有 Fiddler、Dummynet、Clumsy 等。

Wiremock 也支持延迟的功能,比如使用 withFixedDelay() 可以实现固定延迟的效果:

stubFor(get(urlEqualTo("/api/json/cet/now")).willReturn( 
        aResponse() 
                .withStatus(200) 
                .withFixedDelay(2000)));

使用 withLogNormalRandomDelay() 可以实现随机延迟效果:

stubFor(get(urlEqualTo("/api/json/cet/now")).willReturn( 
        aResponse() 
                .withStatus(200) 
                .withLogNormalRandomDelay(90, 0.1)));
数据初始化和构造的成本高

上述对数据持久层集成测试的方法虽然通用,但是将数据库进行初始化需要编写大量的样例代码,插入预期的数据也需要编写大量的数据库操作语句。面对这个问题,可以使用一些现成的持久化测试框架来改善测试体验,常见的持久化测试框架有 NoSQLUnit、DBUnit 等。

DBUnit 的设计理念就是在测试之前,先备份好数据库,再给对象数据库植入需要准备的数据,在测试完毕后,再读入备份数据库,初始化到测试前的状态。DBUnit 可以在测试用例的生命周期内来对数据库的操作结果进行比较。DBUnit 支持的数据库有 db2、h2、mssql、mysql、oralce、postgresql 等。

NoSQLUnit 是用 DBUnit 类似的方式来编写 NoSQL 数据库的测试。支持多种 NoSQL 数据库,包括 HBase、MongoDB、Redis、ElasticSearch、Vault、Neo4j 等。

总结

本节课讲解了微服务架构下的集成测试定义,接着讲解了微服务下的集成测试的两个方面:网关组件层集成测试和数据持久层集成测试。

  • 在网关组件层集成测试中,通过服务虚拟化技术来实现对外部服务能力的模拟,通过模拟网络异常情况来构造外部服务超时、响应慢的情况。

  • 在数据持久层集成测试中,通过持久化测试框架可以避免常规持久化测试时编写大量代码和大量 SQL 语句的情况。

当然,如上框架和工具的威力不限于此,文中只给出了关键的示例信息,你可以根据需求或兴趣自行探索学习。

你负责的模块或服务里,是否进行过集成测试,进展如何,欢迎在留言区评论。同时欢迎你能把这篇文章分享给你的同学、朋友和同事,大家一起来交流。

相关链接:
集成测试
https://en.wikipedia.org/wiki/Integration_testing
https://martinfowler.com/bliki/IntegrationTest.html
https://www.martinfowler.com/articles/microservice-testing/

服务虚拟化工具
WireMock: http://wiremock.org/
Hoverfly: https://hoverfly.io/
Mountebank: http://www.mbtest.org/

持久化测试工具
DBUnit:http://www.dbunit.org/
NoSQLUnit: https://github.com/lordofthejars/nosql-unit

网络模拟软件
Dummynet: https://github.com/luigirizzo/dummynet
Clumsy: https://jagt.github.io/clumsy/cn/index.html


精选评论

**鼠:

微服务集成测试与接口测试有什么区别与联系?

    讲师回复:

    微服务集成测试,主要是关注当前服务与数据持久层和网关组件层的“集成”,不针对当前服务进行测试。
而日常我们所说的服务端接口测试,通常是通过接口调用来测试业务逻辑,从定义和测试层级上看不包含微服务测试策略中的集成测试,接口测试比较偏向于微服务的组件测试、契约测试和接口层面的端到端测试。

**霞:

老师,你好,有个问题有疑问,麻烦您解答一下。文中提到的测试替身和微服务虚拟化技术有什么区别?我理解二者都是对被测对象要使用或调用的函数或对象进行模拟,已摆脱测试依赖的手段,不知道这样理解对不对。二者有什么区别呢?提前感谢。

    讲师回复:

    你的理解找到了两者在软件测试领域中的共通之处。严谨一些的话,不建议直接去对比它们,因为两者的定义或命名不是一个范畴的。测试替身也分很多种,可以是方法级别、类级别或服务级别等,而微服务虚拟化技术能实现服务级别的测试替身效果,当然,微服务虚拟化技术的用途也很广泛,不仅仅只能用于测试替身。

**霞:

老师你好,有个疑问,麻烦解答下。文章中提到集成测试需要测试微服务与外部服务的通信,所以理想情况下不应该使用测试替身。但后面有提到,当服务不可用时,解决方案是微服务虚拟化技术,文中又给出了wiremock构造外部服务的例子。我的问题是:使用wiremock的这种方案,不就是测试替身吗?那何来使用微服务虚拟化技术完美解决外部服务不可用的情况?

    讲师回复:

    理想情况下,确实不应该使用测试替身,但是,如果依赖服务不可用的情况,测试过程是阻塞的,而在微服务架构下这种情况极为常见,所以可以先用测试替身来解决因为依赖导致的联调或测试阻塞,等真实服务可用了再基于真实服务进行测试和验收,这样会比较好。

**0796:

1.请问集成测试是开发还是测试做?2.接口测试是不是包括了集成测试?

    讲师回复:

    1 集成测试是测试人员来做。
2 接口的定义通常很广,因此接口测试的定义也是如此。而日常我们所说的服务端接口测试,通常是通过接口调用来测试业务逻辑,从定义和测试层级上看不包含集成测试,比较偏向于组件测试、契约测试、和接口层面的端到端测试。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

05 集成测试:如何进行微服务的集成测试? 的相关文章

随机推荐

  • 分布式事务的几种解决方案

    一 基础概念 1 什么是事务 事务可以看做是一次大的活动 它由不同的小活动组成 这些活动 要么全部成功 要么全部失败 2 本地事务 在计算机系统中 更多的是通过 关系型数据库来控制事务 这是利用数据库 本身的事务特性来实现的 因此叫 数据库
  • 【干货】Redis在Java开发中的基本使用和巧妙用法

    Redis是一款高性能的内存数据结构存储系统 能够支持多种数据结构类型 如字符串 哈希 列表 集合 有序集合等 也能够支持高级功能 如事务 发布 订阅 Lua脚本等 具有高可用性 高并发性和可扩展性的优点 在Java开发中 Redis可以作
  • Javascript编程语言-现代模式,“use strict“,变量,命名变量,常量,保留字

    现代模式 use strict 长久以来 JavaScript 不断向前发展且并未带来任何兼容性问题 新的特性被加入 旧的功能也没有改变 这么做有利于兼容旧代码 但缺点是 JavaScript 创造者的任何错误或不完善的决定也将永远被保留在
  • sqlmap的使用 (以封神台题目为例)

    一 sqlmap选项 目标 至少要选中一个参数 u URL url URL 目标为 URL 例如 http www site com vuln php id 1 g GOOGLEDORK 将谷歌dork的结果作为目标url 请求 这些选项可
  • Linux— 网络编程套接字

    目录 预备知识 认识端口号 理解源端口号和目的端口号 认识TCP协议 认识UDP协议 网络字节序 socket编程接口 socket 常见API sockaddr结构 sockaddr 结构 编辑 sockaddr in 结构 in add
  • C++ 多线程编程(一)- C++11中的线程类

    C 多线程编程 一 C 11中的线程类 1 C 11 多线程编程库 2 线程的创建 2 1 初始化构造函数 2 2 移动构造函数 3 线程的基本操作 3 1 join 阻塞 等待线程结束 3 2 detach 分离线程 1 C 11 多线程
  • 腾讯云时序数据库 CTSDB 开放公测

    欢迎大家前往云 社区 获取更多腾讯海量技术实践干货哦 作者 李晓慧 近日 腾讯云推出云上时序数据库CTSDB Cloud Time Series Database CTSDB 是一款分布式 可扩展 高可靠的时序数据库 适用于有海量时序数据的
  • 数组的常用方法总结

    获取指定数组的长度 arr length console log a b c length 3 通常情况下 如果想判断一个数组是否为空 可以通过数组的长度是否为零来判断 数组和字符串的相关转换 2 1 数组转换为字符串 console lo
  • HW SR505红外传感器模块 一直输出高电平

    重点 1 505检测的是物体移动 不是前面是否有人 如果一个人一动不动也是不会检测出来的 2 505的正脚必须接5v 如果接3 3v则会不灵敏 505输出脚高电平总是3 3v 如果out引脚一直输出高电平试一下接 5v 3 505输出一次高
  • 主业外的第二副业选什么比较好,适合普通人的坚持之路

    说到副业 可能大部分人觉得不知道应该做什么 只是因为在物质日益高涨的今天 单单靠上班的一份工资已经不足以实现自己的一些人生规划了 上班永远是别人给你的职位 随时可以让你失去它 真正的经济自由是靠自己 所以需要在工作之余发展一份自己的副业 来
  • linux系统 InfluxDB安装及配置,修改数据路径,傻瓜教程

    linux系统磁盘挂载教程 linux服务器磁盘挂载 新手手把手教学 傻瓜式教程 风电猿的博客 CSDN博客 START 1 安装包下载 提供1 8 0版本的Influxdb安装包 百度网盘 请输入提取码 qlyx 2 安装指令 yum l
  • 关于maven仓库中的_remote.repositories

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 问题描述 既然有这个jar包为什么还会报错呢 无意间通过dependency tree命令查看依赖 发现 这说明 core common jar包依赖paas thirdp
  • Node.js-Gulp的使用

    概述 Gulp 是基于 Node 平台开发的前端构建工具 主要用来设置程序自动处理静态资源的工作 通过 Gulp 能自动化地完成 html css javascript less sass image 等文件的测试 检查 合并 压缩 格式化
  • 单个按键控制数码管显示数字(2)

    一 主要功能 单个按键控制数码管显示数字 二 代码实现 代码如下 include
  • Unity3D实现简单的血条功能

    在游戏中血条是一个很常见的东西 它可以直观的显示血量 在很多地方都有运用 尤其是小兵或者怪物身上 那么该怎样去制作一个简单的血条呢 其实很简单 血条就是一个UI而已 用一张长条形的图片即可实现 具体操作如下 1 先创建一个3D的物体命名为P
  • web项目----实现简单的增删查改

    本人稀土掘金地址 coding Rayce 的个人主页 动态 掘金 juejin cn 首先了解javaEE的三层架构 由图中我们可以看出 javaEE的三层架构严格的规定了项目中的每个模块 每个层需要完成的事情 这样会使项目的变得非常简洁
  • gtest使用入门(6)-win下使用vscode和cmake构建

    文章目录 概述 一 环境准备 二 源码准备 三 准备googletest源码和测试代码 四 构建并编译源码和测试代码 五 执行测试 六 总结 七 源码获取 概述 最近尝试在windows下使用googletest 并使用CMake进行构建
  • 计算机网络习题(数字数据编码为数字信号)

    计算机网络习题 数字数据编码为数字信号 题目描述 画出非归零编码 曼切斯特编码 差分曼切斯特编码 知识点分析 非归零码 用高 低电压分别来代表 1 0 二进制 相反也可以 曼彻斯特编码 将一个位 位是指一个比特 即上图中两个虚线之间的范围称
  • GeoGebra

    文章目录 一 GeoGebra简介 1 GeoGebra在线图形计算器 2 GeoGebra应用 3 在线资源平台 二 官方网站 1 GeoGebra官网 2 GeoGebra项目源码 3 GeoGebra官网教程 3 1 Learn Ge
  • 05 集成测试:如何进行微服务的集成测试?

    上一课时 我讲解了微服务架构下的单元测试 它是一种白盒测试技术 目的是验证软件代码中的每个单元 方法或类等 是否符合预期 本节课我来讲解微服务架构下的集成测试 集成测试的概念 说到集成测试 相信每个测试工程师并不陌生 它不是一个崭新的概念