随着Web系统的大规模发展,Web API已经成为了一种广泛使用的技术,再加上微服务和云系统的普及,Web API的数量呈几何增长。比如在一个大型Web系统中,各个子系统或者依赖系统之间一般都使用Web API来集成,从而导致开发不同子系统或者依赖服务的团队之间也存在不少问题。其中最大的四个问题是:

  • 团队之间业务和技术集成沟通困难
  • 难以快速响应外部需求变化
  • 开发流程责任链混乱
  • Web API部署到测试环境后才发现集成问题

这四个问题都属于集成和变更管理的问题,首先团队之间业务和技术集成沟通困难主要是指没有明确的集成沟通流程,那么团队之间在沟通集成业务和技术的时候则容易混乱不清,遇到各种困难。所以需要有一个规范和明确的沟通流程,从而避免有流程混乱所产生的困难。

其次对于难以快速响应外部需求变化,指如果系统的用户提出一个新需求或者需求更改的时候,很难快速的让所有后端开发团队们都明确的知道集成部分的更改细节和需求,从而快速的完成开发工作。

对于开发流程责任链混乱,指对一个子系统很多的应用系统,如果发现一个集成相关的问题,很难确定是哪个子系统的问题。需要有一种方法可以快速的确定应该由谁来修复这个集成问题。

最后Web API部署到测试环境后才发现集成问题,导致发现问题的时间延后,从而增加修复的成本。所以最好能在Web API的编码开发阶段就发现集成问题,从而可以快速反馈,节约修复成本。

在各种测试方法中,契约测试可以较好的解决上面四个问题。但是业界能真正实施契约测试的团队却很少,比如Google,REA等一些国外大型互联网公司的项目以及一些大型正规的金融项目等。而其他绝大部分没有实施契约测试的项目,主要是因为它们还能接受上面四个问题以及这四个问题所带来的成本。

什么是契约测试

契约测试,顾名思义是基于契约或者使用契约来测试被测系统,其核心是契约,包括如何制定契约,如果更改契约以及如何使用契约等。首先定义契约必须有API的消费者(Consumer)和API的提供者(Provider)两端,其次契约还要包含这个API的Request和Response的定义细节,见下图:

img

然后再分别使用这个契约里面的内容生成测试用例来测试消费者者对于Web API消费代码和提供者对于Web API的实现代码,见下图:

img

所以契约测试即测试了一部分接口的功能,也测试一部分集成的功能,但是它却不能完全替代接口测试或者集成测试,因为一般情况下契约测试不会包含所有的业务场景,因此它们之间的关系应该如下图:

img

契约测试存在一些的问题

虽然如此简单的契约测试能解决不少问题,但是它仍然存在一些问题,其中包括:

  • 无法取代功能性的接口测试或者集成测试
  • 沟通,开发和维护成本不低
  • 小项目中的ROI不高

很明显,契约测试最大的困难点就是契约制定和变更的沟通,所以沟通困难的团队并不适合做契约测试。除此以外,没有明确的变更管理流程;或者有团队可以不用遵守契约或者契约的变更流程;或者还不稳定,变更非常频繁的项目都不适合做契约测试,强行做则是事倍功半。

契约测试的主要实践

如果要实践契约测试,首先要沟通契约,并且编写契约。

首先沟通契约一般有两种方式,一种是提供者驱动(Provider Driven),另一种是消费者驱动(Consumer Driven)。而编写契约的方式也有两种,一种是使用工具手动编写契约;另外一种是使用特定的契约测试框架或者工具,然后编写代码来动态生成契约。业界最常用的三个契约测试框架是Pact,Swagger和Spring Cloud Contract。其中Pact是一个支持多种语言的框架,包括Java,JavaScript,Golang,#C等多种语言开源免费框架,主要通过编写测试代码来动态生成契约,并主要用于消费者驱动契约类型的测试;而Swagger主要是通过手动编写契约来做提供者驱动契约类型的测试;最后Spring Cloud Contract主要用于基于Spring框架开发的Web系统,也是主要通过编写测试代码来动态生成契约来做消费者驱动契约类型的测试。并使用契约生成相应的测试用例和自动化测试。

其次,当生成了大量的契约之后,一定要集中化的管理契约,并且最好能可视化出来,如下图:

img

最后将相应的自动化契约测试加入持续构建流水线中进行持续测试。

总结

契约测试是一种相对简单的测试方法,它能解决不少问题,但是它也会带来一些问题,并且如果要成功实施也需要相应的前提。所以一个项目是否选择契约测试,需要先判断项目所遇到的问题是不是适合用契约测试来解决,然后才决定,而不要盲目的选择契约测试。但是项目真的有一些很严重的问题适合用契约测试解决,也不要因为契约测试所带来的一些额外成本而拒绝它,从而得不偿失。

最后契约测试实施的主要步骤总结如下:

  • 制定明确的契约沟通,设计和变更流程
  • 各服务开发团队之间必须同意并遵守此流程
  • 集中化管理契约
  • 可视化展现服务的依赖和调用链
  • 自动化契约测试并加入持续构建流水线中