微服务契约测试

背景

日常开发过程中,项目的接口通常由服务提供方约定和提供,微服务模式下接口被多个消费者调用更是常态,那么提供方接口的变更如何快速、高效、无遗漏的通知给消费者呢?另外,当一个service同时被多个使用者调用,如何保证对service的修改可以让其它所有使用者造成的影响都能被感知到?这些问题契约测试可以给你答案。

测试问题

假设我们有一个由多个微服务组成的应用程序,如下图所示:

Multiple Microservices

如果我们想测试服务间通信时,通常有两种方式:

  1. 部署所有微服务并执行端到端测试
    • 优点:
      • 模拟生产(真实集成场景)
      • 测试服务之间的真实通信
    • 缺点:
      • 要测试一个微服务,我们必须部署其他相关的微服务,数据库及其他基础设施
      • 运行时间过长,当其他服务不稳定或者请求时间过长时,就会导致测试效率很低,稳定性下降
      • 反馈不及时
      • 难以调试
  2. 在单元/集成测试中MOCK其他微服务(构建测试替身)
    • 优点:
      • 快速反馈
      • 没有基础设施要求
    • 缺点:
      • 无法确保接口变动的安全性和准确性
      • 测试可以通过但到生产时会失败(当内部系统测试都通过时,如何能保证真正的外部API没有变化?)

Spring Cloud Contract契约测试的出现就是为了解决上述问题。主要思想是为您提供非常快速的反馈而无需建立整个微服务链路,使用存根(替身),您唯一需要的就是您直接使用的应用程序,下图显示了存根与应用程序的关系:

SCC Stubs

契约测试分两种类型,一种是消费者驱动,一种是提供者驱动,其中最常用的,是消费者驱动的契约测试(Consumer-Driven Contract Test,简称 CDC)。核心思想是从消费者业务实现的角度出发,由消费者端定义需要的数据格式以及交互细节,生成一份契约文件,然后生产者根据契约文件来实现自己的逻辑,并在持续集成环境中持续验证该实现结果是否正确。

对于基于Restful API的微服务来说,它的契约就是指 API 的请求和响应的规则:

  • 对于请求,包括请求URL、请求头、请求内容等

  • 对于响应,包括状态码、响应头、响应内容等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
request:
method: POST
url: /api/orders
bodyFromFile: request.json
response:
status: 201
bodyFromFile: response.json
matchers:
body:
- path: $.retCode
type: by_equality
- path: $.retData.qrCode
type: by_regex
predefined: url

Contract DSL Dynamic properties

Contract DSL Dynamic properties in Body

This section is valid only for the Coded DSL (Groovy, Java etc.)

1
2
3
4
5
6
7
8
9
org.springframework.cloud.contract.spec.Contract.make {
request {
method(POST())
url($(consumer('/rest-producer/api/books'), producer('/api/books')))
}
response {
status(OK())
}
}

Contract DSL Regex

This section is valid only for Groovy DSL.

Contract DSL Matchers

SCC契约测试集成

SCC UML Diagram

契约测试能给我们带来什么?

  • 降低服务集成的难度:把服务集成这个过程分解成了更细的单元测试和接口测试,它从消费者的需求为出发点,把消费者的需求作为测试用例驱动实现一份契约,然后验证提供者端的功能;

  • 开发并行,提高开发效率:契约隔离了消费者和提供者,双方可以并行开展工作,开发过程中就利用契约进行预集成测试,不用等到联调再来集成调通接口,一旦成熟,在保证质量的前提下,联调的成本可以减低到几乎为0;

  • 服务接口变更快速感知,确保变动的安全性和准确性:只要有变化,契约测试即可第一时间发现,保证安全和对接的准确性。

总结

在微服务模式下,服务间的调用关系复杂,契约测试是保证服务提高质量的重要手段之一,因此建议充分利用。

参考链接