业界认为应该让契约测试来替代集成测试。认为你写的2-5%的集成测试和单元测试有重复,或者和其它地方的集成测试存在重复,而且当集成测试失败时,你也不知道发生了什么,不能及时准确定位问题。
一、什么是契约测试
微服务要求有低耦合、高内聚的边界,通常我们使用 DDD 的限界上下文作为微服务边界;而契约测试则是针对这个边界的测试。契约测试是验证服务的Provider是否按照期望的方式与服务的Consumer进行交互,简单的说是Consumer与Provider两者之间的集成。而Contract即合同、契约,就是Provider与Consumer的交互方式。
契约测试通常是基于Consumer驱动的(Consumer Driven Contracts,基于Consumer驱动的契约测试工具有PACT)。基于Consumer驱动的契约测试分两个阶段:1)Consumer生成契约,开发者在Consumer端写测试时Mock掉Provider,运行测试生成契约文件;2)Provider验证契约,开发者拿契约文件直接在Provider端运行测试进行验证。
二、契约测试的特点
1)开发人员编写,采用Mock机制,开发本地就可以运行,没有真实调用,运行快,毫秒级修复反馈周期短;2)Provider与Consumer两两之间的验证,容易定位问题,而且与底层测试或其它契约之间没有重复;3)不需要部署真实的集成环境,稳定且成功率高;4)沟通成本低。(比如一个Consumer端的加入导致服务端API修改,服务端开发人员不必跑去找所有其它Consumer端开发人员沟通确认是否会被影响,直接运行契约测试就能知道结果。
三、扩展
1)还有一个概念叫做design by contract,它规定软件设计人员应为软件组件定义正式、精确和可验证的接口规范,该规范应使用前提条件、后置条件和不变式来扩展抽象数据类型的普通定义。
2)霍尔逻辑中,霍尔三元组对理解程序更友好;P和Q是断言,C是命令 。P叫做前置条件,Q叫做后置条件。霍尔三元组简单理解为:只要P在C执行前的状态下成立,则在执行之后Q也成立。
{P} C {Q}
3)联想到solid原则的里氏替换原则,子类不应该破坏父类定下来的契约。当你发现一个子类没有办法完全替换其父类且并不改变原有的assertion的时候, 你就不该让它们有继承关系.
四、集成测试
端到端集成测试(简称集成测试)是指系统集成后的自动化测试,是系统或模块真实组装后运行的测试。很多团队用UI端到端来测系统集成后的行为,这类工具很多,比如有Selenium webdriver等。端到端的集成测试反馈与修复的周期比较长、运行速度慢,测试运行不稳定,有时随机失败,维护成本也很高。它不像单元测试,单元测试测具体一个方法或API,定位准确,采用Mock机制,运行速度非常快(毫秒级),又是开发人员在本地执行,反馈修复及时,成本较低。
集成测试的特点:1)真实安装后测试,测试更接近真实使用情况;2)可见性强,容易理解;(比如:看一遍运行关键业务的集成测试,业务人员或客户会觉得很放心。也可以替代验收测试);3)模块真实调用,测试运行慢,秒级别或分钟级别,反馈与修复的周期慢,成本高;4)问题定位难,多个子模块组合安装后的测试,很难定位是哪个模块出的问题;5)真实的安装或环境搭建,不稳定,容易导致测试随机失败;6)沟通成本高,需要不同模块团队间的协调工作;7)与底层测试或集成测试会有重复,集成测试中有的路径已经被单元测试覆盖。