微服务自动化测试的测试策略 - Web 3.0 Cloud-Streams 产品级敏捷

标签: | 发表时间:2021-12-05 21:19 | 作者:
出处:https://www.deva9.com

前言:

微服务遵循著单一责任 (Single Responsibility) 的设计原则, 使得微服务较传统的单体 (Monolithic) 能更容易的独立发布、部署。另一方面, 微服务能拥有更大的空间去选择适合自身的编程语言、技术。最重要的一点是, 微服务的架构更容易的能做到 “水平扩展”。

然而, 微服务也有它的技术挑战需要克服。

如图一所示, 微服务的架构是分布式的, 在这样的分布式的架构下, 所谓的 “自动化测试” 将是微服务能否成功的一个首要且关键的要素。

我们将以一系列的文章来探讨微服务自动化测试的策略、方法、工具。首先, 我们从微服务的测试策略谈起。

图一:微服务; 分布式的架构

本文: 

 在谈微服务的自动化测试策略前, 我们需先一起共同的来探讨: 微服务内的架构、微服务与微服务间的协作。然后, 我们就可以探讨微服务需要那些类型的自动化测试。

图二: 微服务内部的主要元素

如图二所示, 微服务的内部主要是由以下的元素所组成:

  • Resources: 主要的责任是经由所选择的协议; 如: REST; 将微服务所提供的服务暴露给微服务的 Client。Resource 会完整性的校验由微服务的 Client所传过来的请求 (Request), 并且将微服务执行完某个服务后的结果, 按照由协议所界定的响应 (Response) 格式; 如: JSON; 提供给微服务的 Client。
  • Service layer:主要的责任是派工给多个的 Domain, 以共同的完成微服务Client 的请求。Resource 完整的校验由微服务的 Client 所传过来的请求(Request) 后, 假如, 此请求会需要自身微服务内部或外部的微服务多个的Domain 才能完成时, Resource 便会将此请求, 交由 Service layer 来处理。Service layer 便会派工给多个的 Domain。当此请求需要调用到外部的微服务时, Service layer 便会藉由 Gateways去传递个请求 (Request) 到外部的微服务。
  • Domain: 主要的责任是专注在微服务业务逻辑的处理。Domain 会将处理完业务逻辑后的结果, 传回给 Resources。
  • Gateways: 主要的责任是使有关连; 会发生调用; 的微服务可以连接起来。Gateways 引导著来自自身微服务的 Service layer 的请求 (Request), 到另一个或多个的外部的微服务, 并且将外部的微服务的响应 (Response) , 传回给自身微服务的 Domain。Gateways 则是藉由 HTTP client 处理微服务间的 HTTP 协议上的请求-响应 (Request-Response)。
  • Data mappers/ORM: 主要的责任是将微服务内的对象持久化。

微服务与微服务间的协作

微服务是能独立发布、独立部署的; 但, 绝不是 “孤立而行”。也就是说, 我们往往是需要多个的微服务来共同提供一具备商业价值的特性; 如图三所示。

图三: 多个微服务共同提供一具备商业价值的特性

对于由多个微服务共同提供一具备商业价值的特性的自动化测试, 我们需考量:

  • 多个微服务是由一个以上的团队在负责开发时,如何确保某个团队开发的节奏、自动化的测试, 不会影响到其他团队的微服务的发布、布署? 我们将在 “能独立发布、独立部署微服务的团队阵型” 一文中再作探讨。

微服务自动化测试的类型

  • 单元测试(UNIT TESTING)

微服务自动化测试中的单元测试, 也是以单个或多个相关的类 (Class) 为测试的单元。

微服务自动化测试中的单元测试, 也是分成为两类:

  • 社交型的单元测试 (Sociable unit testing): 主要是专注测试模块接口的行为是否正确? 而将以类 (Class) 为单元的测试, 当成是黑盒。在微服务自动化测试中, Domain往往是采用社交型的单元测试。因为, 往往我们需要多个Domain 来完成某个微服务 Client 的请求。
  • 单独型的单元测试 (Solitary unit testing): 主要是专注测试单个类/ 对象和它的依赖间的行为是否正确? 我们往往会将单个类/ 对象的依赖以 Mock 或Stub 的方式来替代。在微服务自动化测试中, 我们往往会将相对独立就能完成自身任务的 Resources, Service layer, Data mappers/ORM, Gateways, HTTP client 采用单独型的单元测试。

社交型的单元测试, 单独型的单元测试对于保障 “单一个” 微服务内部的质量, 扮演著重要且关键的角色。

对于保障 “多个” 微服务间的所谓 “系统层级” 的行为正确, 我们将要藉助:

集成测试 (Integration Testing), 组件测试 (Component Testing), 契约测试 (Contract Testing), 端到端测试 (End-To-End Testing)。

  • 集成测试 (Integration Testing)

在微服务自动化测试中, 所谓的集成测试 (Integration Testing) 主要是测试微服务内的模块能否与外部的微服务或外部的数据库正常的 “通信” ? 而不是在测试外部的微服务或外部的数据库。

所以, 在微服务自动化测试中的集成测试, 只需测试关键路径上成功/ 异常的场景即可。

如图四所示, 在微服务内的 Gateways/ HTTP client, Data mappers/ORM 需执行微服务自动化测试中的集成测试。

  • Gateways/ HTTP client  的集成测试: 主要是测试微服务内的模块能否与外部的微服务连接, 并且检测通信协议上的问题; 如: 丢失 HTTP 的表头, 不正确的 SSL 处理, request/response 不匹配。关键的一点是: 所有错误处理的场景一定要都能被覆盖测试到。在后面的文章中, 我们也将会探讨运用 Service virtualization 测试关于 timeout 或者外部微服务延迟响应等的场景。
  • Data mappers/ORM  的集成测试: 主要是测试微服务外部的数据库内的数据表结构是与微服务所期望的数据表结构是一致的。Data mappers/ORM 的集成测试, 对于 NoSQL 的数据库是相当重要、且必要的测试。
图四: 集成测试 (Integration Testing)
  • 组件测试 (Component Testing)

微服务自动化测试中的组件测试 (Component Testing), 指的是: 微服务自身的测试; 以微服务作为测试的单元。

在组件测试 (Component Testing) 中, 测试的粒度是微服务对外的API; 从微服务Client 的视角, 测试微服务对外的API 的行为是否符合预期?

在组件测试 (Component Testing) 中, 将会以 test doubles (mock/ stub) 的方式, 隔离微服务对外的依赖。

  • 如图五所示, 在组件测试 (Component Testing) 中, 为了隔离微服务对外的依赖, Gateways 被配置成去调用 HTTP Client Stub; HTTP Client Stub 将会取代外部的微服务, 而对请求 (Request) 做出响应 (Response)。
  • 如图五所示, 在组件测试 (Component Testing) 中, 我们会以 In-Memory 数据库; 如: H2; 取代外部数据库。这样的作法, 毫无疑问的, 将大幅的提升组件测试 (Component Testing) 执行的速度。

在后面的文章中, 我们将会探讨如何以 Arquillian 实现组件测试 (Component Testing) 。

图五: 组件测试 (Component Testing)
  • 契约测试 (Contract Testing)

微服务是能独立发布、独立部署的; 但, 绝不是 “孤立而行”。也就是说, 我们往往是需要多个的微服务来共同提供一具备商业价值的特性。

当微服务是扮演提供服务的角色时, 我们便称此微服务是 “Producer”。

当微服务是扮演使用服务的角色时, 我们便称此微服务是 “Consumer”。

微服务自动化测试中的契约测试 (Contract Testing), 会在 Producer 微服务与Consumer 微服务之间, 定义一契约 (Contract)。

契约测试 (Contract Testing) 便会根据 Producer 微服务与 Consumer 微服务之间的契约, 测试 Producer 微服务与 Consumer 微服务之间的交互行为是否正确?  Producer 微服务上代码的修改, 是否会影响到 Consumer 微服务, 而使 Consumer 微服务无法再运行?

如图六所示:

  • Producer 微服务提供了 Resource: {id, name, age}。
  • 根据 Contract A, Consumer 微服务 A, 使用了 Producer 微服务, 取得了 Resource: {id, name}。
  • 根据 Contract B, Consumer 微服务 B, 使用了 Producer 微服务, 取得了 Resource: {id, age}。
  • 根据 Contract C, Consumer 微服务 C, 使用了 Producer 微服务, 取得了 Resource: {id, name, age}。

在某一天, 一个新的 Consumer  微服务 Y, 要求 Producer 微服务提供: last name, first name

  • Producer 微服务的开发人员, 便将 Producer 微服务中的 name 栏位(属性) 改成 name 类(对象); 封装著 last name, first name。
  • 经由契约测试 (Contract Testing), Producer 微服务的开发人员将能立马的发现, 他(她) 在 Producer 微服务上的修改, 将会影响到 Consumer A 微服务与 Consumer C 微服务, 而使 Consumer A 微服务与 Consumer C 微服务无法再运行。

在后面的文章中, 我们将会探讨如何以 Pact 实现契约测试 (Contract Testing)。

契约测试 (Contract Testing)
  • 端到端测试 (End-To-End Testing)

微服务自动化测试中的端到端测试 (End-To-End Testing), 主要是要覆盖产品中从前端 GUI 到微服务的测试。

微服务自动化测试中的端到端测试 (End-To-End Testing) 开发与维护的成本是相当的高的。

在后面的文章中, 我们将会探讨如何以 Arquillian 实现端到端测试 (End-To-End Testing)。

图七: 端到端测试 (End-To-End Testing); 从前端 GUI 到微服务的测试

测试金字塔 (Test Pyramid)

在了解了各种类型的微服务自动化测试后, 我们就可以将各种类型的微服务自动化测试, 放入测试金字塔 (Test Pyramid) 中。

如图八所示, 测试金字塔 (Test Pyramid) 可以帮助我们知道如何的去平衡 “测试成本” 与 “测试粗粒度”。

在测试金字塔 (Test Pyramid)中, 越往上升, 所代表的是: 测试的粗粒度越大, 但测试的成本 (测试执行时间) 就越高 (越长)。

 所以, 在 微服务自动化测试的测试策略应该是:

  • 在测试金字塔 (Test Pyramid) 中, 越往上升的测试类型, 其测试的粗粒度就越大, 而其测试的数量应递减。
  • 反之, 在测试金字塔 (Test Pyramid) 中, 越往下行的测试类型, 其测试的粗粒度就越小, 而其测试的数量应递增。
  • 在微服务自动化测试中, 测试数量最多的测试应该是: 单元测试 (UNIT TESTING)
  • 在微服务自动化测试中, 测试数量最少的测试应该是: 端到端测试 (End-To-End Testing)
图八: 测试金字塔(Test Pyramid)

结论:

在分布式架构下的微服务, 要进行自动化测试是件相当复杂的工程。

软件工程界的巨擘; Martin Fowler; 提供了微服务测试的指引。

我们可­根据 Martin Fowler 所提供的微服务测试的指引, 制订我们微服务自动化测试的测试策略。我们后续的文章, 也将会根据 Martin Fowler 所提供的微服务测试的指引, 探讨如何运用相关的测试框架、工具, 以实现微服务自动化测试。

參考資料

  • Testing Strategies in a Microservice Architecture; Martin Fowler
  • Microservices Patterns; Chris Richardson
  • Testing Java Microservices; Alex Soto Bueno, Andy Gumbrecht, Jason Porter

相关 [微服务 自动化 测试] 推荐:

微服务自动化测试的测试策略 - Web 3.0 Cloud-Streams 产品级敏捷

- -
微服务遵循著单一责任 (Single Responsibility) 的设计原则, 使得微服务较传统的单体 (Monolithic) 能更容易的独立发布、部署. 另一方面, 微服务能拥有更大的空间去选择适合自身的编程语言、技术. 最重要的一点是, 微服务的架构更容易的能做到 “水平扩展”. 然而, 微服务也有它的技术挑战需要克服.

iPhone App自动化测试

- BeerBubble - Taobao QA Team
         无线客户端的发展很快,特别针对是android和ios两款无线操作系统的客户端应用,相应的测试工具也应运而生,这里主要给大家介绍一些针对iPhone App的自动化测试工具.          首先,我们把这些测试框架分为三大类:接口测试工具、注入式UI测试工具、录放式UI测试工具.

Android Robotium自动化测试

- - CSDN博客移动开发推荐文章
1、官方网站下载测试工程demo. 从 http://code.google.com/p/robotium/downloads/detail?name=ExampleTestProject_v3.6.zip 下载官方的Android测试工程demo. 解压后的文件NotePad、NotePadTest、readme.txt.

Android UiAutomator 自动化测试

- - 操作系统 - ITeye博客
一、一个BUG引发的问题.     如果研发过程中有一个BUG:“不断的切换手机语言出现花屏现象”. 我想,最好的方式应该是自动化测试.     那么,自动化测试可以完成哪些任务呢.     简单的说,那些重复性的测试工作,都可以交给自动化完成:.         1、设置手机的语言.         2、添加、删除、收藏联系人.

Robotium 自动化测试

- - CSDN博客推荐文章
Robotium 自动化测试. Android Studio环境下,在所要测试的Module的build.gradle文件下添加,. Robotium即是对Instrumentation框架方法的封装,所以使用之前需要继承测试类,重写构造器,setUp()和tearDown()方法. 其中继承的是ActivityInstrumentationTestCase2测试类.

Android自动化测试解决方案

- Haides - InfoQ中文站
现在,已经有大量的Android自动化测试架构或工具可供我们使用,其中包括:Activity Instrumentation, MonkeyRunner,Robotium,以及 Robolectric. 另外LessPainful也提供服务来进行真实设备上的自动化测试.

InstrumentDriver,对iOS自动化测试说 Yes!

- - Taobao QA Team
    InstrumentDriver 是 Mobile自动化小组最近实现的基于 instrument,针对 iOS 的自动化测试框架,目前支持 java 语言编写测试用例.     研究过iOS自动化测试的同学肯定对 instrument UI Automation 有所耳闻,或者已经使用它进行自动化测试实践.

菜鸟学自动化测试(九)----WebDirver

- - 博客园_首页
关于什么是WebDirver,上一节做了简单的描述,环境也在上一章中搭建完成. 下面我们拷贝了官网提供的一个实例. 让其在我们的eclipse中运行. Selenium WebDirver 代码如下:. // 用Firefox driver创建一个新的的实例. //注意:其他的代码依赖于界面. WebDriver driver = new FirefoxDriver();// 这里我们可以使用firefox来运行测试用例.

无用的自动化测试

- - CSDN博客研发管理推荐文章
自动化测试,特别是UI级的自动化测试是一件费力而不讨好的事情. 自动化测试使得测试人员疲于应付,朝不顾夕,如坐针毡,苟延残喘. UI级的自动化测试看起来很美好,就像罂粟,如果你经不住诱惑冒然尝试,那么后果很严重,下场很惨淡. 也许这个世界上就不应该出现自动化测试这个东西,起码在中国不应该出现,因为这个是无效的,无用的,宿命是失败的东西.

前端自动化测试探索

- - FEX 百度 Web 前端研发部
测试是完善的研发体系中不可或缺的一环. 前端同样需要测试,你的css改动可能导致页面错位、js改动可能导致功能不正常. 由于前端偏向GUI软件的特殊性,尽管测试领域工具层出不穷,在前端的自动化测试上面却实施并不广泛,很多人依旧以手工测试为主. 本文试图探讨前端自动化测试领域的工具和实践. 一个项目最终会经过快速迭代走向以维护为主的状态,在合理的时机以合理的方式引入自动化测试能有效减少人工维护成本.