任务 1:练习 API 契约测试
最后更新于
最后更新于
Hey,你好,我是 JimmyLv 吕靖,这是你开始 前端 TDD 练习的第 15 天。今天你将会开始练习 Bookshelf 项目,我们会从一个简单的 RESTful API 入手,使用契约驱动开发的方式模拟和验证前后端协作。
在团队内部,前后端协作本质上需要的不是一份 API 文档,而是一个可以供前后端共同遵守的契约。前后端开发人员可以一起制定一份契约,使用这份契约共同开发,前端使用这份契约启动 mock API,后端则可以通过它简单的验证 API 是否正确输出想要的数据。
契约测试本质上也是一种 TDD,契约驱动开发,双方先定契约,你做你的 我做我的,契约可以自动化执行,检测双方是否达成契约要求。
Pact 测试又名契约测试,是消费者服务与生产者服务之间的消费者驱动测试,消费者驱动的契约测试(Consumer-Driven Contracts)。
契约可以理解为反向的录像机(VCR)。 VCR 记录实际的提供者行为,并验证使用者的行为是否符合预期。 Pact 记录消费者行为,并验证提供者的行为是否符合预期。
当然,我还通过 CodeSandbox 的方式作为你的快速入口:https://codesandbox.io/s/github/JimmyLv/tdd-bookshelf (可能需要科学上网),帮助你去除设置开发环境的障碍,一键打开 Cloud IDE 即可开始编码,右边则是你的网站运行效果预览,比如:https://tdd-bookshelf.jimmylv.now.sh/
举个例子,我们需要实现:
GET /api/books
- Retrieve all books (with query?)
GET /api/books/{id}
- Retrieve a single book detail by ID
由于我们没有真正去实现一个 Provider 来提供 API,所以从前端的角度我们期望方便快捷得启动一个 Mocker Server。
在我们平常的前端开发当中也会用到 mock server,现在让我们把这个 mock server 改造一下,引入测试先行的概念,变成即可以提供 mock 数据,又可以作为契约自动化验证后端 real API,这样一举两得了。
参考资料:
理解契约测试当中的 Consumer 和 Provider,以及 contract 契约文件。
设计符合 REST 规范的 API,参考文章:什么才是真正的 RESTful 架构?
契约先行,通过测试生成 mock server 再进行前端页面的业务开发。
也许你也能够明白这一点,契约测试只是替代了部分的系统集成测试(即确保正确使用 API 以及 API 以期望的方式进行响应)。但是它并不会取代其他维度的测试,金字塔结构中的其他测试侧重点不同,保障的是应用程序的其他核心业务逻辑能够正常工作。
那么,请你从契约测试的运行速度的角度思考一下,这个 Pact 测试跑起来快嘛?API 测试跟单元测试的运行速度有什么区别?分别有什么目的和侧重点?适用于什么样的场景?
下一步,如果你需要从软件开发的全局上下游考虑问题,你该如何向后端 API 开发人员(如果你们采取前后端分离的开发模式)解释契约测试呢?如何让双方理解前后端契约的价值并在项目中推行呢?
尝试了解一下 Pact Broker,有了它之后,后端如果再悄咪咪改 API 字段,公共的 Pact Broker 瞬间就晓得了,契约这一层属于中间层,有点中间人的意思,当然它还可以映射各服务之间的调用关系。
使用 Pact Stub server 的办法直接开启前端开发的进程,摆脱对后端 API 环境未 Ready 的依赖。那么更进一步,是时候将契约测试推广到后端,跟后端开发小伙伴共同约定一份契约,放到 Pact Broker 以及 CI 用来辅助 API 开发吧!
其实 Cypress 也可以 Stubbing the server,但是我建议不要在 E2E 框架层面 mock 任何东西,要防止因为 API 层面挂掉,而导致前端无法继续开发,或者持续集成无法进行。
但是,我们要尽可能让前端的 mock server 跟后端的 real server 保持一致,这样在每次后端(Provider) API 变更时都能够测试是否满足前端的需要,又能够在前端(Consumer)的角度检查 API 是否破坏了既有需求,从而保障约定好的契约与实际实现能够正确执行。
理解一下 Functional Testing vs Integration E2E Testing 的区别,前者其实是可以在前端利用 mock server 保障前端的功能不会挂,即 API 数据供给永远都是好的,我们测试的是前端的数据显示与交互功能是否正常如初;而后者则更偏向于端到端的功能集成测试,当整个应用出现错误异常,有可能是前端出现问题,有可能是后端 API 出现问题,也有可能是前后端各自安好,但是对接出现问题。
这时,出现 Bug 时我们就要去定位问题,而我们会发现,问题发现得越晚,其修复成本越高。我们得去逐一排查:前端界面 -> 前端数据流(Store) -> 前后端集成 -> 后端 API 数据 -> 后端数据库,然后去是不是前端有问题,如果前端没问题那就再切换视角到后端,而如果前后端当前的优先级不一致,就会导致各自排查的积极性不足,而导致前端等后端,后端怪前端的尴尬境地。测试驱动开发,让我们可以从契约测试出发,先定义好契约然后用自动化的方式去保障和追踪 API 接口变更是否满足预期,对比一下,再想想你们做前后端联调时的痛苦吧!
参考资料: