【玩转 Postman 接口测试与开发2_017】第13章:在 Postman 中实现契约测试(Contract Testing)与 API 接口验证(下)
《API Testing and Development with Postman》最新第二版封面
文章目录
- 第十三章 契约测试与 API 接口验证
- 8 导入官方契约测试集合
- 9 契约测试集合的详细配置
- 9.1 env-apiKey 的创建与设置
- 9.2 env-workspaceId 的设置
- 9.3 Mock 服务器及 env-server 的配置
- 9.4 API 测试实例的配置
- 9.5 契约测试脚本的调试
- 10 Postman 拦截器的用法
- 11 契约测试的运维
写在前面
本文为第 13 章笔记的下篇,详细介绍了本书最新版中引入的契约测试模板的具体用法,并结合本地实测情况给出了大量截图。相信随着 Postman 官方对该模板的升级改造,具体的操作很可能和本文介绍的操作步骤有所不同,但这并妨碍我们了解契约测试的构建过程和相关细节。我们要学习的从来不是某个按钮的位置、某个脚本在哪儿书写,而是透过这些表象操作,能够从宏观层面构建完备的关于契约测试的知识体系。毕竟在 AI 时代的大背景下,我们应该学会主动和 AI 合作,不断调整自学的重点,不断更新 “重复造轮子” 的内涵。
(接上篇)
第十三章 契约测试与 API 接口验证
8 导入官方契约测试集合
虽然 API 标签页中的接口实例已经实现了 OpenAPI
规范和集合层的双向检查,但真正的契约测试还需要在请求前后以测试用例的形式确保各个接口的定义和功能相契合,还得要开发者针对不同的 API 集合编写大量性质相同的定制化脚本。正如第一版中看到的那样,这一步看似轻松,实现起来却非常繁琐。
为此,Postman
官方发布了一个专门用于契约测试的公共集合 Contract Test Generator
,经过这几年的不断更新迭代,目前已经能够实现对目标集合实施无侵入式的契约测试,极大地省去了从零开始手写契约测试脚本的麻烦。该集合的灵感最初来自 GitHub
社区开发者 allenheltondev 于 2020 年 10 月 9 日贡献的一个开源项目 postman-contract-test-generator,由于解了大家的燃眉之急,开源后不久就被 Postman
官方复刻到 自己名下 进入长期维护并持续迭代。这就是开源的魅力——既方便了后来者,也让项目本身更加完善,同时也提高了开发者自身的影响力。本章唯一美中不足的,应该就是书中漏掉了大量的配置细节,实测时踩了不少的坑(当然也不排除从出书到实测这段时间差里,项目本身的更新迭代导致配置出现些许差异)。无论如何,我都将重新完整梳理一遍这个彩蛋级福利的用法,也算为开源社区略尽绵力吧。
首先从官方社区导入这个测试集合。在 Postman
顶部的搜索框中检索关键字 Contract Test Generator
就可以看到基于 OpenAPI v3.x
规范的测试集合 (Generator) Contract Tests - OAS3
:
【图 13.9 在 Postman 的顶部搜索框检索契约测试生成工具】
点击后将打开对应的 API 首页,并通过右边的 Fork 按钮复刻到自己的帐号下:
【图 13.10 从生成工具的文档首页点击 Fork 复刻到自己帐号下】
然后在弹出的新页面确认 Fork 的相关配置,其中务必勾选与该集合关联的测试环境:
【图 13.11 Fork 操作时务必勾选对应的测试环境(非常重要)】
复制到自己名下后将在 Collection
导航页看到这样的结构:
【图 13.12 复刻到自己帐号下看到的契约测试集合结构】
9 契约测试集合的详细配置
该集合的工作原理也很简单,只要配置好测试环境中的相关参数,就能通过运行 Collection Runner
一次性得到目标集合的契约测试结果。当然,它只实现了契约测试最基本的校验逻辑,开发者可以在此基础上做进一步补充,比起从零开始编写已经好很多了。
以下是此次实测(截至 2025 年 2 月 5 日)需要补全的环境变量(先选中 Contract Test Environment
环境):
变量名 | 变量值 |
---|---|
env-apiKey | 当前个人帐号生成的有效 API 秘钥 |
env-workspaceId | 当前工作空间的唯一标识 |
env-server | 目标集合的服务器基础 URL,也可以是该集合对应的 Mock 服务器的基础 URL |
env-apiId | 目标 API 的唯一标识 |
env-apiDefinitionId | 目标 API 定义唯一标识 |
书中只讲了前三个变量,其实还有很多隐含信息:
- 为了配置示例 API 的
env-server
,需要 先创建一个对应的 Mock 服务器,并填入该 Mock 服务器的URL
;否则使用导入时默认的http://localhost:5000/budgeting/api
会报错; - 新版的
Generator
集合必须先发布一版API
,即指定一个API
版本号,否则后面有个Validate API In Workspace
请求也会报错; - 契约测试脚本中大量使用旧版
Postman
的断言写法,需要逐一改为最新的版本,导入必要的npm
模块(例如lodash
等);
下面逐一进行说明——
9.1 env-apiKey 的创建与设置
首先是 env-apiKey
:为安全起见,生成的 Mock 服务器都设为私有服务器,用自己帐号生成的 API 秘钥进行加密。
【图 13.13 点开 Postman 右上角的个人帐号图标,从浏览器进入对应的设置页面】
【图 13.14 找到 API keys 导航页,按 Generate API Key 按钮生成秘钥】
【图 13.15 输入一个秘钥名称,以便后续管理(如 DemoContractTesting)】
【图 13.16 复制秘钥妥善保管(注意:新生成的 API 秘钥只有一次机会可供复制,错过后只能重新生成)】
【图 13.17 秘钥生成后,可在列表中找到该记录,可从右边的隐藏菜单中重新生成或删除】
然后就可以赋给 env-apiKey
变量(顺便将该变量的类型设为 secret
):
9.2 env-workspaceId 的设置
当前工作空间的 ID,从首页右侧的隐藏菜单项 Workspace info
获取:
9.3 Mock 服务器及 env-server 的配置
找到 Collection
侧边栏,从测试集合 Budgeting API
的隐藏菜单中创建 Mock 服务器:
然后填入环境变量:
最后别忘了还要将该 URL
更新到 API 实例中的 YAML
定义文件中:
以及最初导入 YAML
文件时自动创建的测试集合变量 baseUrl
(这个坑非常隐蔽,浪费了很多次 Collection Runner
免费额度才发现问题):
9.4 API 测试实例的配置
根据契约测试生成工具的最新版本,目标 API 实例需要先发布一个版本,具体操作如下:
发布后的 API 实例首页如下图所示:
接着,点击上图右侧的图标,找到 API 对应的唯一标识,以及 API 定义层的唯一标识(后续契约测试有用):
【图 13.18 从 API 实例的详情信息栏找到对应 API 唯一标识与定义层标识】
然后粘贴到环境变量中:
9.5 契约测试脚本的调试
完成测试环境 Contract Test Environment
的配置后,为了提高 Collection Runner
的一次性通过率,接下来需要手动发送一遍契约测试集合中的每个请求,一边学习不同的测试脚本的写法,一边打开 Postman
的控制台,根据警告信息完善脚本。实测时发现的主要问题包括:
Using "_" is deprecated. Use "require('lodash')" instead.
:- 解决方案:新版
lodash
模块需要显式声明,需要在脚本开头处添加一句:const _ = require('lodash');
- 解决方案:新版
Using "postman.setNextRequest" is deprecated. Use "pm.execution.setNextRequest()" instead.
- 解决方案:按提示改为最新版写法即可:
pm.execution.setNextRequest()
- 解决方案:按提示改为最新版写法即可:
接着,就可以启动 Collection Runner
了:
【图 13.19 完成环境配置和脚本微调后,就可以启动契约测试集合的 Collection Runner 了】
第一次运行后,部分请求测试不通过:
【图 13.20 首次运行后,部分请求校验未通过(有意为之)】
根据断言提示,主要发现三类问题:
Schema
对象名称的首字母没有大写:Schema 'item' begins with an uppercase letter | AssertionError: expected 'i' to equal 'I'
;Schema 'items' begins with an uppercase letter | AssertionError: expected 'i' to equal 'I'
;Schema 'itemId' begins with an uppercase letter | AssertionError: expected 'i' to equal 'I'
- 缺失
description
属性问题:Schema property 'item.transaction_date' has a description between 10 and 100 characters | AssertionError: expected { type: 'string', format: 'date' } to have property 'description'
; - 缺失
example
属性问题:Schema property 'item.transaction_date' has an example | AssertionError: expected { type: 'string', format: 'date' } to have property 'example'
。
根据这些断言提示,回到 YAML
定义文件逐一修改后(重要提醒:不仅是定义的地方要改,所有引用了该定义的地方也要同步更新):
再次运行 Runner
:
【图 13.21 按要求修改 YAML 文件后,再次运行 Collection Runner 进行验证(全部通过测试)】
10 Postman 拦截器的用法
拦截器的作用:可用于捕获契约测试中实际用到的集合请求。
拦截器可作为逆向工程的一部分反观实际调用的接口请求,但由于需要安装 Chrome
插件,用户体验较差,仅供参考。
11 契约测试的运维
契约测试的主要目的:确保 API 提供者在修改 API 时不会违反接口契约。
责任划分:API 消费端可 偶尔运行 契约测试;主要责任仍在 供应端。
契约测试的运行
- 供应端:
- 这些测试应作为 API 开发团队的构建流程的一部分运行。
- 可参考第 9 章构建基于命令行的契约测试运行模式。
- 消费端:
- 不需要在每次更改时运行测试,因为用户界面的更改通常不会影响 API 的工作方式。
- 可利用
Postman
的监视器机制定期检查 API 是否仍符合合同,参考第10章(使用 Postman 监控 API)。
契约测试失败的原因分析
- 存在 bug:需更新代码,修复 Bug。
- 需求变更:API 可能需要以违反契约的形式进行更改。此时需要相关方进行沟通并更新契约。
契约测试的共享:
- 必要性:合同测试需要由提供者和消费者共同访问和维护。
- 共享方式
- 创建一个专门的工作空间(
Workspace
)来存储和共享合同测试。 - 设置工作空间的可见性为团队,并邀请相关人员加入。
- 共享合同测试集合到该工作空间,并分配不同的角色权限(如管理员、查看者、编辑者)。
- 创建一个专门的工作空间(
- 注意事项:免费版
Postman
账户有请求共享限制,大量合同测试可能需要升级到付费计划。
后记
Postman 官方发布并长期维护的契约测试集合(Generator) Contract Tests
极大地简化了 API 接口契约测试的难度,让测试人员和开发者有个可以学习参考的基础模板;尽管如此,也要清醒地意识到,想要真正发挥好契约测试的作用,还得多方参与,从长计议。毕竟当中的很多问题并非几行测试脚本就可以轻松解决的。