背景
在当前微服务和前后端分离大行其道的行业背景下,越来越多的团队采用了前后端分离和微服务的架构风格。
该服务架构下会让各个服务之间更多的依赖关系,而且通常每个服务都是独立的团队维护,服务和服务之间大多通过API调用。那么这种情况下可能就会出现一个问题,想象一下以下的场景:
A团队开发某服务并提供对应API服务,B团队是A团队的使用者调用A团队的API。
image.png
A团队埋头苦干,B团队也争分夺秒,两边都开发完了,往往一联调,就出现下图这情况。
image.png
为了保证API调用的准确性, 我们需要对API进行测试。但是即使这次测试通过了,可能会随着迭代的演进,重构等,A团队可能无形中修改了原API,那么这就可能会让B团队在不知情的情况下服务不可用。
对测试而言也可能因为A团队未完成对应API服务或者A服务不稳定,而照成测试无法介入B团队的测试或者测试效率低下。
当然你可能为了早点让B团队可测,你可能构建测试替身,例如使用MockService,构建A团队的服务替身。看上去貌似可以测试提前又可以避免A服务的不稳定性,但是问题又来了,即使Mock测试通过了,你能确定AB团队联调就能通过?也许A团队返回的根本不是你Mock类型的数据或者说A团队的服务发生了变化。
image.png
问题和困境
- API调用方对API提供方的变更经常需要通过对API的测试来感知。
- 直接依赖真实API的测试效果受限与API提供方的稳定性和反应速度。
解决方案
解决方式首先是依赖关系的解耦,去掉直接对外部API的依赖,而是内部和外部系统都依赖于一个双方共同认可的约定—“契约”,并且约定内容的变化会被及时感知;其次,将系统之间的集成测试,转换为由契约生成的单元测试,例如通过契约描述的内容,构建测试替身。这样,同时契约替代外部API成为信息变更的载体。
image.png
什么是契约测试
契约测试也叫消费者驱动测试。
两个角色:消费者(Consumer)和 生产者(Provider)
一个思想:需求驱动(消费者驱动)
契约文件:由Consumer端和Provider端共同定义的规范,包含API路径,输入,输出。通常由Consumber生成。
实现原理:Consumer 端提供一个类似“契约”的东西(如json 文件,约定好request和response)交给Provider 端,告诉Provider 有什么需求,然后Provider 根据这份“契约”去实现。
PACT demo 分享
PACT 工作原理
PACT 是契约测试其中一个主流框架,最早是ruby实现,现支持大部分开发语言,下图是PACT的工作原理图
image.png
第一步:Consumer 写一个对接口发送请求的单元测试,在运行这个单元测试的时候,Consumer 会向Pact发起一个请求,Pact会将服务提供者自动用一个MockService代替返回,并生成Json格式的契约文件。
第二步:在Provider端做契约验证测试。将Provider服务启动起来以后,通过一些命令,Pact会自动按照契约生成接口发起Provider服务调用请求,并验证Provider的接口响应是否满足契约中的预期。
所以可以看到这个过程中,在消费者端不用启动Provider,在服务提供端不用启动Consumer,却完成了与集成测试类似的验证测试。
转载:https://blog.csdn.net/xkjit/article/details/102013974