首先是依赖关系的解耦,去掉直接对外部API的依赖,而是内部和外部系统都依赖于一个双方共同认可的约定—“契约”,并且约定内容的变化会被及时感知;其次,将系统之间的集成测试,转换为由契约生成的单元测试,例如通过契约描述的内容,构建测试替身。这样,依赖契约的测试效率优于集成测试,同时契约替代外部API成为信息变更的载体。
对于契约来讲,行业内比较成熟的解决方案是基于YAML标记语言的Swagger Specification(OpenAPI Specification),或者是基于JSON格式的Pact Specification。
通常的做法是API的提供者使用“契约”的形式,将功能发布在公共平台,给调用方进行说明和参考,这里我们可以暂时称之为Provider-Driven-Contract。这种做法的潜在问题是,功能提供方的API返回内容是否都满足所有API调用者的需求不得而知。所以,针对这个问题,依赖关系再一次反转,契约测试就摇身一变成为了Consumer-Driven-Contract test(CDCT), 通过给API提供方提供契约的形式,来完成功能的实现。
契约测试的维度
1. 测试覆盖范围对比(纵向)
-
单元测试:对软件中的基本组成单位的测试,大多数是方法函数的测试,运行速度快。
-
契约测试:对服务之间的功能进行的测试,运行速度基本与单元测试相同。
-
E2E 测试:对系统前后端或者不同系统之间的集成测试,大多通过模拟UI操作的方式实现,运行速度三者之中最慢。
2. 测试效率对比(横向)
-
环境依赖:
单元测试:程序集
契约测试:程序集、依赖契约文件、虚拟路由服务
端到端测试:程序集、真实路由服务、前端UI
-
运行速度: 单元测试 > 契约测试 > 端到端测试
Pact官方给出的几个场景:
适用场景:
-
团队能把控开发过程中的Consumer和Provider端
-
适合Consumer驱动开发的场景
-
对于每个独立的Consumer端,Provider端都能管理好需求。
不适用的场景:
-
公共API或者是OAuth授权服务
-
Provider端和Consumer端没有良好的沟通渠道
-
针对性能的测试
-
Provider端的功能性测试(Pact只测试内容和请求格式)
-
对于不同输入有相同的输出,并未达到验证的目的
-
当前测试输入需要依赖之前测试返回的结果
以上对比说明契约测试所要解决的问题是替代系统之间的集成测试,通过契约和单元测试的方式加速系统运行。同时也说明契约测试存在一些不适用的场景,要依据使用场景区别对待。契约测试没有取代单元测试以及E2E测试。