十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Postman接口自动化测试实战:从集合、断言到Newman持续集成

Postman接口自动化测试实战:从集合、断言到Newman持续集成 1. 从手动点按钮到自动跑用例Postman 自动化测试到底改了什么事很多人对 Postman 的印象还停留在调试接口的工具填个 URL选个方法点 Send看 JSON 返回。这是它的基本功但远不是全部。作为接口测试领域最常用的工具之一Postman 内置了一整套接口自动化能力从断言校验、变量管理、数据驱动到批量执行和命令行运行几乎覆盖了接口自动化测试的完整链路。这套能力用好了完全可以承担中小型项目的接口回归任务也是很多团队搭建接口自动化测试体系的第一站。如果你只是拿 Postman 手动发请求那说明还没有真正用到它的测试能力。Postman 的自动化核心由三个部分组成集合Collection负责组织用例环境变量和全局变量负责在不同请求间传递数据脚本Script负责断言和逻辑控制。三者配合才能把一个个手动点变成一次跑完所有接口。我见过不少团队接口测试已经做起来了但方式还是我先手动调通一个然后复制 N 遍改改参数再一个个发。这本质上仍是手工测试只是把请求工具从浏览器换成了 Postman。真正的接口自动化至少要满足两个条件第一用脚本自动断言不靠人眼去看返回结果第二能批量执行不需要人守在屏幕前一次次点 Send。Postman 恰好把这两个条件都做到了而且没有引入额外的编程门槛。1.1 三个基本单元集合、变量、脚本把三个基本单元拆开理解整个 Postman 自动化测试的骨架就清楚了。集合是请求的容器也是测试用例的容器。你可以把针对同一个系统、同一个模块的一批接口请求全部放进一个集合里集合内还可以建文件夹用来区分正向用例、异常用例、边界用例。集合级别支持统一配置 Pre-request Script 和 Tests 脚本意味着同一批用例共用的初始化逻辑比如通用的鉴权头、签名逻辑可以只写一次不用在每个请求里重复粘贴。环境变量和全局变量解决的是环境差异问题。开发环境、测试环境、预发布环境之间往往只是域名和个别参数不同。把这些差异点提取成变量用例里只用{{变量名}}引用就能做到一套用例在多个环境之间无缝切换。这是接口自动化里非常重要的设计思路用例和环境解耦。环境变了只改环境配置不动用例。脚本是 Postman 自动化测试的执行引擎。每个请求都挂了两个钩子发送前可以执行 Pre-request Script拿到响应后可以执行 Tests。两个阶段都能读写变量也能通过内置的pm对象访问请求、响应、环境等信息。断言本质上就是用 JavaScript 写的测试逻辑所以凡是写过一点点 JS 的人上手都不难。1.2 与 Jmeter 等方案的边界在哪聊 Postman 自动化测试很难不提到 Jmeter。很多人一上来就在 Postman 和 Jmeter 之间反复纠结。我的理解是Postman 更偏向测试开发场景脚本语言是 JavaScript上手快做接口调试和中小规模的自动化测试非常顺手Jmeter 更偏压测和复杂场景编排学习曲线陡但在性能测试、分布式压测上有明显优势。如果你的目标是尽快把接口回归自动化跑起来Postman 加 Newman 通常是最短路径如果你要做并发模拟和性能摸底Jmeter 是更合适的选择。还有一个现实因素Postman 客户端是图形界面脚本写起来直观调试时能直接看到每个请求的预览、请求头和响应体。团队里新手测试、开发转测试的同事通常十分钟就能上手。这样的工具属性决定了它非常适合作为接口自动化的起点。2. 把底子打好集合、环境变量与全局变量的设计细节自动化测试最怕的不是写断言而是用例的可维护性太差。刚上手的人往往把所有请求平铺在一个集合里URL 里的 HOST 全部写死参数也写死。跑通了还好一旦换环境、改接口地址改起来就是噩梦。所以第一步一定是把底子设计好而不是急着写断言。2.1 集合的创建与分层思路打开 Postman左侧栏点 New Collection命名建议遵循系统名-模块名规则比如电商后台-订单模块。集合下面继续建文件夹区分正向用例、异常用例、边界用例。这个分层和你平时在测试用例管理工具里写的用例层级保持一致后面维护时才不会乱。创建集合后点集合右侧的省略号选择 Edit在 Tests 和 Pre-request Script 标签页中可以配置集合级别的公共脚本。公共逻辑放这里有几个好处不会重复写修改一处整个集合生效新人接手时只看一个地方就能理解全局行为。关于客户端本身如果你刚下载安装直接在官网拿到安装包装好就能用。界面默认是英文对英文不敏感的人可以去设置里把 Language 切成中文Postman 的新版本支持部分中文显示不影响核心功能。2.2 变量作用域与选择策略在说变量之前先理解 Postman 的作用域。Postman 里变量有多个级别全局变量Global、环境变量Environment、集合变量Collection、数据变量Data、局部变量Local。读取变量时按局部 数据 环境 集合 全局的优先级查找。什么时候用哪种变量我的实际经验如下全局变量放所有环境都不变的内容比如接口协议版本号、某些全局唯一标识。环境变量放环境相关的差异项比如接口域名、数据库连接串、某个环境特有的账号。集合变量放当前集合下各接口共用的上下文数据比如登录后获得的 token。数据变量数据驱动时来自 CSV/JSON 的每一行参数。局部变量一次脚本执行内部临时用到的值脚本跑完即销毁。设置环境变量的方式很简单点右上角的眼睛图标进入 Manage Environments新建一个环境填好变量名和初始值。在请求 URL、请求头、请求体里都可以用双大括号{{变量名}}引用。这里我建议在环境变量里单独建一个字段叫api_host值为http://test-api.example.com所有请求的 URL 都写成{{api_host}}/api/orders这样的形式换环境时只需要切换环境配置完全不用改请求内容。2.3 动态数据与常用脚本片段接口测试中经常需要生成唯一的数据Postman 内置了一些动态变量可以直接用{{$guid}}生成一个 UUID。{{$timestamp}}当前时间戳。{{$randomInt}}随机整数。{{$randomEmail}}、{{$randomUserName}}随机邮箱、随机用户名。这些内置动态变量可以直接写在请求体里省去写随机函数的麻烦。不过要注意一点{{$guid}}这类变量在每次发送时都会重新生成如果你希望同一个值在断言和后续请求中都保持不变就应该先把动态值存到一个变量里再引用。例如在 Pre-request Script 中pm.variables.set(orderNo, ORD pm.variables.replaceIn({{$timestamp}}));请求体里写{ order_no: {{orderNo}} }后面的断言如果要用到这个订单号同样通过pm.variables.get(orderNo)获取保证同一个用例内数据一致。2.4 一份可复用的集合目录示例下面是我在真实项目中习惯使用的集合目录结构参考价值比较高ProjectName集合 ├── 00_通用登录、获取 token、基础配置 │ ├── 登录获取token │ └── 刷新鉴权信息 ├── 01_用户模块 │ ├── 创建用户正向 │ ├── 创建用户重复名称异常 │ ├── 查询用户列表 │ └── 更新用户信息 ├── 02_订单模块 │ ├── 创建订单 │ ├── 订单流转依赖编排 │ └── 订单查询数据校验 └── 03_支付模块 ├── 发起支付 └── 支付回调模拟这样的结构有几方面好处通用逻辑放在最前面可以被其他文件夹或请求引用正向和异常用例分类存放执行时可以用文件夹粒度来筛选模块间依赖关系通过请求顺序和变量传递来管理。等到用例数量多了这个目录本身就成了接口测试的说明书新人照着目录顺序跑一遍就能了解系统核心接口的用法。3. 断言脚本怎么写才算自动化测试而不是自动发请求这是我认为最能区分会用 Postman和会做 Postman 自动化测试的一道分水岭。很多人发的请求能通但从未认真写过断言导致测试结果里全是请求成功却无法回答业务到底对不对。3.1 请求执行的两个阶段Pre-request Script 与 TestsPostman 中每个请求在执行时脚本按这样的顺序跑如果有集合级别的 Pre-request Script先执行。再执行请求级别的 Pre-request Script。发送请求。收到响应后执行请求级别的 Tests。最后执行集合级别的 Tests。Pre-request Script 适合做请求前的准备生成签名、设置公共请求头、从变量中准备参数甚至实现一次完整的授权刷新逻辑。Tests 则是对响应做断言的地方检查状态码是不是 200、返回体里有没有某个字段、某个字段的值是不是符合预期、响应时间有没有超过阈值。理解两个阶段的分工很多问题都能想明白。比如你需要在登录接口返回后把 token 存起来供后续请求使用那应该在登录接口的 Tests 里写pm.environment.set(token, jsonData.data.token)而不是写在 Pre-request Script 里。因为只有拿到响应后才知道 token 是什么。3.2 常用断言写法与关键 APIPostman 的 Tests 标签页右侧有一个断言片段库点一下就可以插入常用片段。但既然是做自动化测试我建议还是要理解片段背后的写法才不会一出错就手足无措。最基础的几个断言// 检查状态码是否为 200 pm.test(状态码是200, function () { pm.response.to.have.status(200); }); // 检查状态码是否在 2xx 范围内 pm.test(状态码是2xx, function () { pm.response.to.be.success; }); // 检查响应体包含某个字符串 pm.test(响应体包含订单号, function () { pm.expect(pm.response.text()).to.include(order_no); }); // 解析 JSON并校验字段值 pm.test(返回的订单状态是PAID, function () { const jsonData pm.response.json(); pm.expect(jsonData.data.status).to.eql(PAID); }); // 校验响应时间不超过 1000ms pm.test(响应时间小于1秒, function () { pm.expect(pm.response.responseTime).to.be.below(1000); });这些断言看起来简单却是接口自动化的基石。有了它们每次执行用例不需要人去看返回结果脚本会自动告诉你哪些通过、哪些失败。3.3 接口间数据传递把上一个请求的结果带到下一个请求接口自动化最核心的难点之一是处理接口之间的依赖关系。比如创建订单接口返回一个订单号查询订单详情接口必须要用这个订单号。如果请求里写死一个订单号每次执行时数据状态可能对不上用例就不稳定。解决办法是创建订单接口的 Tests 里把订单号写入集合变量查询详情的请求 URL 或请求体里用{{变量名}}引用。创建订单接口的 Tests 写const jsonData pm.response.json(); pm.test(创建订单成功, function () { pm.expect(jsonData.code).to.eql(0); }); if (jsonData.data jsonData.data.order_no) { pm.test(订单号已保存, function () { pm.expect(jsonData.data.order_no).to.not.be.empty; }); pm.collectionVariables.set(orderNo, jsonData.data.order_no); }查询订单详情请求的 URL 写成https://{{api_host}}/api/orders/{{orderNo}}这样整套流程跑下来用例之间通过变量完成数据衔接数据不需要人为准备真正做到一套脚本跑完一个业务链路。3.4 业务断言不要只看 HTTP 状态码很多初学自动化的人只校验状态码这是远远不够的。状态码为 200 只能说明接口没有报系统错误不能说明业务逻辑一定正确。比如创建订单接口HTTP 200但返回体里code可能是 1001代表库存不足这时候你的用例应该失败而不是因为 HTTP 200 就认为通过。所以我的经验是自动化脚本里至少要有一层业务断言校验返回的业务码、关键业务字段、数据条数、字段类型等。这样一旦接口逻辑被改坏脚本能第一时间抓到问题。常见的业务断言写法const jsonData pm.response.json(); pm.test(业务码为0, function () { pm.expect(jsonData.code).to.eql(0); }); pm.test(返回消息是成功, function () { pm.expect(jsonData.message).to.eql(success); }); pm.test(列表数据不少于10条, function () { pm.expect(jsonData.data.list.length).to.be.at.least(10); }); pm.test(金额字段是数字类型, function () { pm.expect(jsonData.data.amount).to.be.a(number); });4. 数据驱动让 10 条用例的成本约等于 1 条用例单条用例写得好只是自动化的第一步。真正的效率提升来自批量复用。4.1 CSV 与 JSON 数据文件怎么选Postman 的 Collection Runner 和 Newman 都支持从外部文件读取数据为同一请求提供多组参数。这个能力叫数据驱动测试。数据文件支持 CSV 和 JSON 两种格式。怎么选我的经验是如果数据量不大、结构清晰用 CSV 更直观用 Excel 就能编辑如果数据里有嵌套结构、数组或者字段经常变化JSON 更灵活不容易因为字段顺序或引号问题解析出错。更关键的一点是CSV 中如果某一行字段为空Postman 会把空值当作空字符串传给接口而不是当作空参数这经常导致意外失败JSON 格式不会出现这种问题。所以我现在默认用 JSON 数据文件。JSON 数据文件示例[ { case_name: 正常创建订单, expect_code: 0, pay_amount: 100.00 }, { case_name: 金额为0, expect_code: 3001, pay_amount: 0 }, { case_name: 金额为负数, expect_code: 3001, pay_amount: -10 } ]请求体里引用数据文件的字段{ pay_amount: {{pay_amount}} }4.2 脚本如何读取数据文件中的值Postman 会把每一行数据放进数据变量中这些变量可以在请求的任何位置用双大括号引用也可以用pm.iterationData.get(字段名)在脚本中获取。如果字段名和已有的环境变量同名数据变量的优先级更高。这一点在调试时非常容易踩坑你以为用的是环境变量里的值实际却被数据文件里这一行的值覆盖了。如果发现数据值不对第一反应可以先看看当前迭代里有没有同名的数据字段。4.3 断言期望值跟着数据走数据驱动最有价值的一点是连断言里的期望值都可以跟着数据走。比如上面 JSON 里的expect_code不同的用例期望不同的业务码。断言写成const jsonData pm.response.json(); const expectCode pm.iterationData.get(expect_code); pm.test(业务码符合预期: expectCode, function () { pm.expect(jsonData.code).to.eql(expectCode); });这样一套接口用例配上一份数据文件就能覆盖非常多的场景。我在实际项目中经常把一个接口的几十条用例全部塞进一个 JSON 数据文件一行对应一条用例。跑完 Runner 就能看到每一条用例的通过率维护成本低可读性也好。4.4 迭代执行时要注意请求重复执行的坑在 Collection Runner 选中集合后拖入数据文件Postman 会显示迭代次数等于数据文件的行数。点击 Run 后每行数据请求一次。结果页面上每个迭代的请求状态、Tests 通过数和失败数都清晰可见点击失败的迭代还能看到具体断言报错信息。这里有一个容易忽略的点默认情况下同一个集合里的所有请求会在每个迭代中按顺序执行一遍。如果你的集合里只有一个请求数据驱动效果很明显如果有多个请求又希望只对其中一个请求做数据驱动就需要在请求级别添加执行条件否则其他请求会在每个迭代里重复执行拖慢整个测试流程还会产生很多无意义的成功结果。常见的做法是在 Pre-request Script 里根据迭代数据判断是否跳过当前请求const shouldRun pm.iterationData.get(run_this_request); if (!shouldRun) { postman.setNextRequest(null); }5. 批量执行与持续集成Collection Runner 和 Newman 的配合自动化测试的价值不在偶尔跑一次而在于可以随时、反复、自动地跑。Postman 提供了两种批量执行方式图形界面的 Collection Runner 和命令行工具 Newman。5.1 Collection Runner本地批量跑接口用例Collection Runner 的入口在集合右侧的下拉菜单和左上角 Runner 按钮。打开后选择要执行的集合或文件夹再配置环境变量、迭代次数、数据文件、请求延迟等。这里有一个建议Runner 默认会按文件夹排列顺序执行请求排列顺序就是执行顺序。这在编排链路用例时非常有用。比如用户模块在订单模块之前创建用户、创建订单、查询订单这类有先后依赖的用例就可以通过调整文件夹顺序来串联。如果希望先执行某个初始化请求再执行其他用例也可以在集合里通过postman.setNextRequest控制跳转。执行完成后会生成一份可视化报告展示每个请求的通过率、平均响应时间、失败详情。这份报告可以导出为 JSON 或 HTML方便归档和分享。5.2 Newman命令行执行与报告生成Newman 是 Postman 官方提供的命令行运行器本质上就是把 Collection Runner 的能力搬到了终端里。安装方式很简单前提是电脑里有 Node.jsnpm install -g newman执行集合newman run 订单模块.postman_collection.json -e 测试环境.postman_environment.json -d data.json参数说明-e指定环境文件-d指定数据文件-n指定迭代次数--reporters指定报告输出格式。生成 HTML 报告通常用 newman-reporter-html 插件npm install -g newman-reporter-html newman run 订单模块.postman_collection.json -e 测试环境.postman_environment.json -r htmlNewman 有一个关键特性只要断言失败进程就会返回非 0 退出码。这个特性对 CI 集成至关重要因为它让流水线能根据测试结果自动判断红绿状态而不需要额外解析报告文件。5.3 导出集合与接入 CI 流水线Newman 集成到 CI 流水线是 Postman 自动化测试能真正发挥持续回归作用的关键。集合文件可以直接从 Postman 客户端导出也可以进到网页控制台同步后从命令行拉取。导出的文件是 JSON 格式包含集合下所有请求、脚本、变量定义这些文件可以提交到代码仓库作为测试资产管理。集成思路通常是在 CI 的测试阶段安装 Newman然后把导出的集合文件、环境文件、数据文件都放在仓库里每次代码提交或定时任务触发时流水线执行 Newman 命令跑完后再把报告上传或发送通知。示例流水线片段如下test: stage: test script: - npm install -g newman - newman run tests/order.postman_collection.json -e tests/env.postman_environment.json -r html artifacts: paths: - newman/Jenkins 上也是类似的思路在构建步骤中加一行 Shell 命令就行。跑完如果没有失败流水线就是绿色一旦接口被改坏流水线立刻变红问题在提测前就被拦住这才是自动化测试真正的价值。需要注意的是导出的集合文件里如果包含敏感信息比如账号密码、token必须处理掉。常见做法是所有值都从环境变量读取导出后检查确认没有明文敏感数据。写代码的人都知道不要把密钥提交到仓库接口测试资产同样不能例外。6. 实战中绕不开的坑从失败定位到环境问题排查写到这里我想把实战中踩过的一些坑单独拿出来说。这些坑非常典型几乎每个做过 Postman 接口自动化的人都会遇到。6.1 接口大面积失败时先检查环境再看脚本跑批量用例时如果出现大面积失败我的第一反应不是怀疑断言写错而是先去确认环境变量是否选对了。Postman 执行时使用右上角当前选中的环境如果环境变量切换错了所有依赖变量的请求都会失败而且报错信息很可能是五花八门容易被误导到别的地方。所以我把一个习惯安利给所有人在集合里放一个最基础的接口比如健康检查或者获取服务器时间不做复杂断言只校验状态码。每次批量执行前先看这个基础接口是否成功。如果它挂了说明环境或配置出了问题不用逐个排查后面几十条用例。6.2 文件上传失败faile to upload file的定位过程很多人在 Postman 里做文件上传接口测试时遇到过faile to upload file或者类似的上传失败报错。这个问题的常见原因有三个。第一请求体里没有把参数类型设置为 form-data而是用了 raw 或 x-www-form-urlencoded。文件上传必须使用 form-data 类型并且 key 列右侧的下拉类型要选择 File。第二文件路径中包含中文名或特殊字符某些后端对文件名的处理比较严格会导致上传失败。建议测试时避免使用中文、空格和特殊字符的文件名。第三文件大小超过后端限制或代理限制报错信息可能不会明确提示是大小问题。可以先拿一个小文件测试确认接口本身正常后再逐步增大文件体积。排查方法很简单用浏览器开发者工具抓一次真实页面上传成功的请求和 Postman 里的请求做对比。重点看 Content-Type 头、form-data 的字段名、文件字段名是否完全一致。大部分上传失败都是细节没对齐而不是接口本身有问题。6.3 非预期弹窗干扰自动化执行的三个处理层次接口自动化测试本身不涉及页面弹窗但在实际工程里自动化测试前后往往还夹杂着 UI 操作或者环境准备这时很容易遇到非预期弹窗导致失败的情况。比如测试环境突然弹出登录超时提示或者浏览器弹出一个确认框自动化脚本原本按部就班执行结果被弹窗卡住持续超时最终用例判定失败。这个问题的根因是测试脚本没有处理预期之外的系统干扰的能力。解决思路一般有三层。第一层预防。执行前把环境清理干净比如关闭系统的自动更新提示、关闭浏览器自动弹窗、杀掉干扰进程。接口自动化测试通常不需要浏览器尽量用 Newman 这样的命令行方式从源头减少弹窗出现的概率。第二层超时与重试。给每个步骤设置合理的超时时间一旦失败立即再次尝试避免一次弹窗导致整个请求链完全中断。在 Postman 脚本中遇到临时失败可以用循环重试的方式直到重试次数耗尽。第三层失败后的降级处理。在脚本中捕获与弹窗相关的异常例如对话框不存在时直接跳过存在时自动关闭后再继续。这样即使出现了一次非预期弹窗脚本也能自动恢复而不是整个任务失败。这个方法不只适用于 Postman所有自动化测试都可以通用。核心思路是不要假设环境永远干净脚本要能容忍偶发的外部干扰。6.4 变量覆盖与作用域一个隐蔽的失败来源变量覆盖是 Postman 脚本里非常隐蔽的坑。前面提到过变量读取顺序局部大于数据数据大于环境环境大于集合集合大于全局。如果环境变量里有一个 token集合变量里也有一个 token脚本里用pm.variables.get(token)读取时实际拿到的会是环境变量里的值而不是集合变量里的值。你可能在集合变量里更新了一个新 token但后续请求拿到的还是环境变量里的旧值于是出现明明写了变量却没生效的诡异现象。另一种情况是在 Pre-request Script 里用pm.variables.set(token, 新的值)设置变量这个操作会把值写进当前作用域但pm.variables.set的写入层级有时候并不直观导致后续请求在其他作用域里读不到。为了避免这类问题我推荐统一约定关键的上下文数据比如 token、订单号、用户 ID全部使用集合变量统一通过pm.collectionVariables.set/get读写并在命名上加统一前缀比如ctx_token、ctx_order_no。这样作用域清晰排查也就方便了。提示如果你发现明明设置了变量但下一个请求取到的还是旧值先检查作用域。设置时用的方法和读取时用的方法不一致是最常见的原因。我个人在实际项目里就是这样一步步从手动点 Send 走到 Newman 接入 CI 的整个过程没有引入重型框架也没有花大量时间搭平台。如果你正准备把接口自动化跑起来我建议先别急着上框架把 Postman 这条链路用透很多时候已经够用了。最后再分享一个小技巧日常调试每条用例时尽量多跑几次 Runner而不是只点 Send。Runner 模式下能看到完整的断言和执行路径Send 模式下看到的只是单次请求的结果两者对用例质量的感知完全不同。我见过太多人调通接口却从没跑过断言直到 CI 报红了才知道 Tests 里写了个永远通过的断言。自动化测试的前提是可信用例本身得先经得起检验。
返回列表