基于消费者驱动的契约测试

JB Rainsberger 曾说过,“集成测试是一个陷阱,它像一个自我扩散的病毒,无情地威胁着代码库、项目和团队。”

随着微服务系统复杂度的增加,集成测试所带来的弊端愈发明显。

1. 运行效率低

由于微服务本身是基于分布式的系统,因此进行集成测试时,每个服务会同运行在其它节点的服务交互,而这类交互通常都是跨网络的。因此,相比进程内的交互或者同一节点内的交互,运行效率低。由其是当服务之间依赖关系复杂时,结果更明显。

2. 运行结果不稳定

对于分布式的系统而言,当进行不同服务间的集成测试时,网络的延迟、带宽可能会影响到测试运行的结果。除此之外,所依赖服务的部署、升级、或者临时不可用,也会导致测试运行的结果不稳定。另一方面,随着依赖服务的不断迭代,接口的变化通常会导致测试结果的失败。

3. 反馈周期慢

从经典的测试金字塔理论来看,集成测试所关注的粒度比单元测试粗。通常,集成测试会将几个不同的服务组合起来进行验证。这也意味着,随着系统的复杂度逐渐增加,服务的数量越多,影响错误的因素也越多,反馈周期也就越长,开发人员需要花费更多的时间去定位错误的原因。

服务间的交互是依赖于互相提供的接口来进行的,那么什么是接口?接口就是服务之间的通信方式和协议,也可以称为契约。契约的两端分别是消费者和提供者。使用契约的一方称为消费者,提供契约的一方为提供者。

当契约发生改变后,那么所有契约的消费者都需要针对这个变化做出调整。

在微服务架构下,这就意味着即便是简单的契约变化,也会使多个使用契约的消费者受到影响。如果测试不及时,可能导致很多服务在测试环境,甚至是生产环境中出现错误。

契约测试是针对服务接口进行的测试,它能验证提供者提供的契约是否满足消费者的期望。在契约测试中,契约主要表现为三部分:

请求:由消费者发出的HTTP数据,包括URL、请求的参数以及HTTP动词等。

响应:主要指提供者应答的HTTP响应。

交互元数据:交互过程中,描述交互状态的数据。譬如提供者的信息、消费者的信息、当前的上下文等。

对于一个服务提供者而言,每个消费者都会根据与其交互的不同,生成不同的契约。当这个提供者被修改时,应该保证每个消费者依然能够正确地消费契约。

契约测试能够提供一个机制去验证组件能否始终满足契约。当涉及的组件是微服务时,接口便是各个服务暴露出来的公共API。每个消费方服务的维护者只需要编写独立的测试套件来验证服务提供方中他所使用的那一部分就可以了。

例如有V0版本的契约,契约提供者和契约消费者能够互相协作,完成业务价值的实现。但是,当提供者提供的接口发生变化,如从V0升级到V1,契约测试就能够立即验证出,提供者当前发布的接口与之前消费者期待的接口不匹配。如下图所示:


通过契约测试,能帮助我们有效地降低微服务接口变化所带来的消费者端的风险。

对于契约而言,消费者消费契约,提供者提供契约。也就是说,当提供者提供的契约能够被消费者消费后,其对应的价值才被实现。对于那些消费者无法消费的契约,并无法真正有效实现价值。即,消费者是价值流中离价值实现最近的。

从消费者出发,以先定义满足消费者的契约作为第一步,就能优先保障价值的实现。如下:

再验证提供者,使其提供的契约和消费者需要的契约一致,如下:


通过如上两个步骤,能有效地保障消费者和提供者协同工作,这就是我们提到的消费者驱动的契约测试。

消费者驱动的契约测试,通常实现方式如下:

1. 选择合适的场景,定义消费者的请求和期望的响应。

2. 使用Mock机制,为消费者提供模拟的提供者以及期望的响应。

3. 记录消费者发送的请求、提供者提供的响应以及关于场景的其它元数据,并将其记录为当前场景的契约。

4. 模拟消费者,向真正的提供者模拟发送请求。

5. 验证提供者提供的契约是否和之前记录的契约一样。

在微服务架构下,基于消费者驱动的契约测试,有两个非常明显的优势。

从价值实现的角度定义契约

从消费者使用契约的角度出发,首先保证消费者基于此契约是可以实现价值的。有了这个前提,再使用契约来验证提供者,如果提供者提供的契约与定义的契约一致,则证明提供者提供的契约是能够服务消费者的。

◎隔离消费者和提供者的测试

有了消费者驱动的契约测试,能够首先保证消费者基于契约是可以实现价值的,从而再通过契约验证提供者提供的契约是否符合要求。在这种情况下,我们可以看出,对于契约的消费者和提供者而言,二者可以分开测试。因此,基于消费者驱动的契约测试,能有效解决之前提到的传统集成测试在微服务架构下存在的弊端,将微服务的测试成本降到最低。

Pack是一个基于消费者驱动的契约测试框架。它的使用主要包括两步:消费者端生成契约与提供者端完成校验。

在消费者端生成契约的主要步骤如下:

1. 消费者端使用Pact框架提供的DSL以及相关的配置文件,运行一个本地的模拟服务,模拟服务的提供者端。

2. 消费者端发送HTTP请求。

3. 提供者端返回响应,供消费者使用。

4. 消费者端和提供者端完成一次交互。Pact框架将当前的请求和响应记录下来,并生成Pact文件,也叫契约。

Pact文件的内容是json格式的,主要记录消费者以及提供者之间的交互过程,包括消费者的请求、参数以及提供者的响应等。

有了消费者端生成的Pact文件,提供者端就可以通过Pact框架提供的DSL以及相关的配置文件,模拟消费者端发送请求,并验证提供者端返回的响应是否和Pact文件中描述的响应一致。

提供者端完成契约校验的主要步骤:

1. 提供者端使用Pact框架提供的DSL以及相关的配置文件,配置Pact

2. Pact框架将模拟消费者向提供者端发送请求。

3. 提供者端返回响应。

Pact框架验证提供者端提供的响应是否与Pact文件匹配。

   综上所述,Pact框架从消费者端出发,先帮助消费者端获取预期的响应,记录交互过程并生成契约,在通过反向验证提供者端。基于这种方式,每当提供者端提供的响应发生变化时,我们就能通过Pact框架以及相关的Pact测试立刻体现出来,帮助我们及早发现服务间接口不一致的问题。


  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值