《微服务架构设计模式》阅读笔记(五)

第9章 微服务架构中的测试策略(上)

测试通常都在开发完成后执行,并且一般都是手动执行的。这种测试方法现在不管用了,原因有两个:

  • 手动测试效率极低:你永远不应该让人类去做一台机器可以做得更好的事情。与机器相比,手动测试执行的速度很慢,不能全天候工作。如果依赖手动测试,你将无法快速且安全地交付高质量的软件。编写自动化测试至关重要。
  • 在交付流程中才进行测试为时已晚:在编写应用程序之后,确实应该通过测试来找出软件潜在的问题,但经验表明这些测试不够充分。一种更好的方式是让开发人员编写自动化测试,以此作为开发的一部分。自动化测试可以提高开发人员的工作效率,例如,当他们在修改代码的时候,自动化测试用例可以给他们提供及时的反馈。

对手动测试的依赖并不是因为缺乏自动化测试的工具和框架。缺乏自动化测试的原因主要是文化:“测试是QA的工作”“开发人员的时间不该用在测试上”,等等。事实上,开发那些能够快速运行并且高效、可维护的测试用例集也非常具有挑战性。而且,一个典型的大型单体应用程序非常难以测试。
使用微服务架构的一个关键动机是提高可测试性。但与此同时,微服务架构的复杂性要求你编写自动化测试。此外,测试微服务在某些方面具有挑战性。因为我们
需要快速验证服务的功能,并且尽量减少缓慢、复杂又不稳定的端到端测试。因为端到端测试常常需要启动一系列互相依赖的服务。

9.1 微服务架构中的测试策略概述

假设你已对FTGO应用程序的Order Service进行了更改。当然,下一步是运行代
码并验证更改是否正常。一种选择是手动测试更改。首先运行Order Service及其所有依赖项,包括基础设施服务,比如数据库和其他应用程序服务。然后通过调用其AP或使用FTGO应用程序的用户界面来“测试”服务。这种测试方法的缺点是既费时又费力。
更好的选择是在开发过程中就引入自动化测试。你的开发工作流程应该是:编辑代码运行测试(理想情况下只需一次击键),然后重复这两件事情。快速运行的测试可以在几秒钟内告诉你更改后的代码是否能正常工作。

9.1.1 什么是测试

如图9-1所示,测试的目的是验证被测系统(System Under Test,SUT)的行
为。在这个定义中,系统只是一个泛称,它指的是被测试的软件元素。它可以小到一个类,大到整个应用,或者介于两者之间,例如一组相关的类、模块或单个服务。一组相关的测试用例集构成一个测试套件。
在这里插入图片描述
自动化测试通常包括四个阶段:

  1. 设置环境:将被测系统以及其他相关元素组成的测试环境初始化为所需的状态。例如创建测试中的类,并将其初始化为呈现特定行为所需的状态。
  2. 执行测试:调用被测系统,例如,在被测试的类上调用一个方法。
  3. 验证结果:对调用的返回结果和被测系统的状态进行判断。例如,验证方法的返回值和被测试类的新状态与预期一致。
  4. 清理环境:必要时清理测试环境。许多测试省略了这个阶段,但是某些类型的测试,比如涉及数据库的测试可能需要在这个阶段将数据库的状态回滚到设置环境阶段前的初始状态。

使用模拟和桩进行测试
被测系统在运行时常常会依赖另一些系统。依赖的麻烦在于它们可能把测试复杂化,并减慢测试速度。例如,Order Controer类调用Order Service,而Order Service又依赖于许多其他应用程序服务和基础设施服务。把整个系统的大部分都运行起来,而仅仅是为了测试一个Order Controer类,这显然是不切实际的。我们需要一种单独测试被测系统的方法。
如图9-3所示,解决方案是用测试替身(Test Double)来消除被测系统的依赖性。测试替身是一个对象,该对象负责模拟依赖项的行为。
在这里插入图片描述
有两种类型的测试替身:桩(stub)和模拟(mock)。术语桩和模拟通常可以互换使用,尽管它们的行为略有不同。桩是一个测试替身,它代替依赖项来向被测系统发送调用的返回值。模拟是也一个测试替身,用来验证被测系统是否正确调用了依赖项。此外,模拟通常也扮演桩的角色,向被测系统发送调用的返回值。(桩用来替代下游给上游返回约定响应,模拟用来替代下游检测上游的请求是否符合约定。)

测试的不同类型
测试通常分为如下四种类型:

  • 单元测试:测试服务的一小部分,例如类。
  • 集成测试:验证服务是否可以与基础设施服务(如数据库)或其他应用程序服务进行交互。
  • 组件测试: 单个服务的验收测试。
  • 端到端测试:整个应用程序的验收测试。

使用测试象限进行分类
分类测试的一种好方法是Brian Marick的测试象限。测试象限(如图9-4所示)按两个维度对测试进行分类:

  • 测试是面向业务还是面向技术:使用领域专家的术语来描述面向业务的测试,使用开发人员的术语和实现来描述面向技术的测试。
  • 测试的目标是协助开发还是寻找产品缺陷:开发人员使用协助开发的测试作为日常工作的一部分。寻找产品缺陷的测试旨在确定需要改进的部分。

在这里插入图片描述
测试象限定义了四种不同的测试类别:

  • Q1协助开发/面向技术:单元和集成测试。
  • Q2协助开发/面向业务:组件和端到端测试。
  • Q3寻找产品缺陷/面向业务:易用性和探索性测试。
  • Q4寻找产品缺陷/面向技术:非功能性验收测试,如性能测试。

使用测试金字塔指导测试工作
我们必须编写不同类型的测试,以确保应用程序有效。但是,挑战在于测试的执行时间和复杂度随着其范围而增大。此外,测试范围越大,其构成部件越多,可靠性就越低。不可靠的测试几乎和没有测试一样糟糕,因为如果你的测试不可信,你就可能会忽略缺陷。
测试金字塔如图9-5所示,是一个很好的指南。
在这里插入图片描述
测试金字塔的关键思想是,在金字塔中从下往上移动时,应该编写的测试越来越少。我们应该编写大量的单元测试和很好的端到端测试。

9.1.2 微服务架构中的测试挑战

在基于微服务的应用程序中,进程间通信比在单体应用程序中起着更重要的作用。
验证两个服务可以交互的一种方法是同时运行两个服务,调用触发通信的API,并验证它是否具有预期结果。这肯定会遇到集成的问题,但它基本上都是端到端的。测试的过程需要运行这些服务的许多其他依赖项。测试可能还需要调用复杂的高级功能,例如业务逻辑即使目标只是测试相对较低级别的进程间通信。最好避免编写像这样的端到端测试。我们需要编写更快、更简单、更可靠的测试,理想情况下可以单独测试服务。解决方案是使用所谓的消费者驱动的契约测试(consumer-driven contract testing)。

消费者驱动的契约测试
消费者契约测试是针对提供者的集成测试,用于验证其API是否符合消费者的预期。
重要的是要记住,契约测试不会彻底测试提供者的业务逻辑。这是单元测试的工作。

9.1.3 部署流水线

每个服务都有一个部署流水线。Jez Humble的名著《Continuous Delivery》将部署流水线描述为把开发人员电脑上的代码部署到生产环境中的一个自动化过程。如图9-9所示,它包含了一系列执行测试套件的阶段,后面是一个发布或部署服务的阶段。理想情况下,它是完全自动化的,但它也可能包含手动步骤。部署流水线通常使用持续集成(ContinuousIntegration)服务器(如Jenkins)实现。
在这里插入图片描述

9.2 为服务编写单元测试

如图9-10所示,单元测试是测试金字塔的最低级别。它们是面向技术的测试,目标是协助开发。
有两种类型的单元测试:

  • 独立型单元测试:使用针对类的依赖性的模拟对象隔离测试类
  • 协作型单元测试:测试一个类及其依赖项
    在这里插入图片描述
    类的职责及其在架构中的角色决定了要使用的测试的类型。图9-11显示了典型服务的六边形架构以及通常用于每种类的单元测试类型。控制器和服务类通常使用独立型单元测试。领域对象(例如实体和值对象)通常使用协作型单元测试。
    在这里插入图片描述

9.2.1 为实体编写单元测试

略~

9.2.2 为值对象编写单元测试

略~

9.2.3 为Saga编写单元测试

略~

9.2.4 为领域服务编写单元测试

略~

9.2.5 为控制器编写单元测试

略~

9.2.6 为事件和消息处理程序编写单元测试

略~

第10 章 微服务架构中的测试策略(下)

编写各类测试的DEMO。
略~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值