Postman接口关联测试:快速串联B2C商城核心业务场景
1. 项目概述:当“逃课”成为一种高效策略
最近在带新人做接口自动化测试的时候,发现一个挺有意思的现象:很多同学拿到一份像“华测B2C在线商城”这样的API接口文档,第一反应是发怵。文档动辄几十上百个接口,从登录、商品浏览、购物车到下单、支付,链路长,参数多,依赖关系复杂。传统的做法是老老实实按文档顺序,一个个接口单独调试,再手动拼凑数据,过程繁琐且容易出错。
于是,我给他们演示了一种我称之为“逃课版”的玩法——不追求对每个接口进行面面俱到的独立测试,而是利用Postman的接口关联功能,快速串联起一个核心业务场景。比如我们这个标题里的“登录-选择商品加入购物单-下单”。这就像打游戏时,不硬刚所有小怪,而是找到一条最优路径,直奔BOSS。对于快速验证业务流程、理解接口间的数据流转,或者给前端开发提供一个可用的“接口串”,这种方法效率极高。
今天,我就以“华测B2C在线商城”这个虚构但典型的项目为例,手把手带你走一遍这个“逃课”流程。你会发现,用好Postman的环境变量、Tests脚本和Pre-request Script,你不仅能跑通流程,更能把过程中的关键数据(如token、商品ID、订单号)动态地传递下去,实现真正的自动化场景测试。这不仅是“逃课”,更是“抄近道”的智慧。
2. 核心思路拆解:接口关联的本质与“逃课”逻辑
在开始动手之前,我们必须先搞清楚两件事:什么是接口关联,以及我们“逃课”的底气从哪里来。
2.1 接口关联:不仅仅是“一个接一个”地调用
很多新手会误解,以为在Postman里按顺序发送几个请求就叫接口关联。这远远不够。真正的接口关联,核心在于数据的动态传递与依赖关系的自动处理。
以一个典型的B2C商城下单场景为例:
- 登录接口:你调用它,服务器返回一个
token(或sessionId)。这个token是你后续所有操作的“通行证”。 - 加入购物车接口:调用它时,你需要在请求头(Header)里带上第一步获取的
token,以证明你的身份。同时,你需要知道你要加购的商品ID和SKU ID。 - 下单接口:调用它时,同样需要
token。此外,它可能需要你提供从购物车接口返回的购物车ID或选中的商品清单。
如果你手动操作,流程是:调登录 -> 从响应里肉眼找到token-> 复制token-> 粘贴到购物车请求的Header里 -> 调购物车 -> 从响应里找到商品或购物车信息 -> 复制 -> 再粘贴到下单请求里……
这太原始了。接口关联要做的是:让Postman自动从上一个接口的响应中提取所需数据,并自动设置到下一个接口的请求中。这样,你只需要点击一次“运行”,整个场景就能自动走通。
2.2 “逃课版”策略的精髓:聚焦主流程,忽略非关键验证
“逃课”不是乱来,而是有策略地省略。在这个“登录-加购-下单”场景中,我们的策略是:
- 目标明确:只验证这三个核心接口串联起来是否能走通,业务逻辑是否基本正确。
- 数据从简:使用文档提供的示例商品ID、或从商品列表接口获取的第一个商品。不纠结于搜索、筛选、商品详情等前置分支。
- 依赖处理:全力解决
token、商品ID、购物车项ID(或订单快照数据)这三个关键数据的动态传递。 - 断言从宽:主要断言HTTP状态码为200/201,以及响应中包含“成功”、“订单号”等关键字段。暂时不深入断言所有业务字段的精确值。
这种策略非常适合:
- 快速冒烟测试:在每日构建后,快速验证核心购买链路是否崩掉。
- 接口联调:前端开发需要一套能跑通的接口集合来调试页面。
- 新人熟悉业务流程:通过一个可运行的实例,直观理解接口间如何协作。
理解了这些,我们的工具选型就毫无悬念了——Postman。它内置的pm对象,提供了在Tests和Pre-request Script中读写环境变量、解析响应数据的强大能力,是实现自动关联的“瑞士军刀”。
3. 环境准备与关键配置
工欲善其事,必先利其器。在开始编写请求之前,我们需要在Postman中搭建好我们的“工作台”。
3.1 创建集合(Collection)与环境(Environment)
- 新建集合:在Postman侧边栏点击“Collections” -> “+”,命名为“华测商城-核心场景测试”。集合就像一个文件夹,可以把我们相关的接口请求都放进去,并且能统一运行。
- 新建环境:这是实现动态关联的核心。点击顶部右侧的“Environments” -> “+”。
- 环境名称:
华测商城-测试环境。 - 添加变量:我们需要预先定义一些变量,即使初始值为空。这是我们的“数据中转站”。
base_url:https://api-test.huace.com(假设的测试环境地址,请根据实际文档修改)access_token: (留空,登录后由脚本填充)product_id: (留空,可以从商品列表获取或使用固定测试商品ID)cart_item_id: (留空,加购后由脚本填充)order_sn: (留空,下单后由脚本填充)
- 环境名称:
注意:务必在发送请求前,在右上角的环境选择下拉框中,选中你刚创建的“华测商城-测试环境”。否则,所有
{{variable}}的引用都会失效。
3.2 解析接口文档,确定关键参数
假设我们从“华测B2C在线商城API接口文档”中摘取出以下三个关键接口(格式为简化版):
1. 用户登录
- 端点:
POST {{base_url}}/api/v1/auth/login - 请求体 (JSON):
{ "username": "test_user", "password": "Test@123456" } - 成功响应 (JSON):
{ "code": 200, "message": "success", "data": { "user_id": 10001, "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "expires_in": 7200 } } - 关键提取字段:
data.access_token
2. 添加商品到购物车
- 端点:
POST {{base_url}}/api/v1/cart/items - 请求头:需要认证
Authorization: Bearer {{access_token}}
- 请求体 (JSON):
{ "product_id": {{product_id}}, "sku_id": "SKU123456", // 示例SKU,实际需根据商品获取 "quantity": 1 } - 成功响应 (JSON):
{ "code": 200, "message": "添加成功", "data": { "cart_id": "CART_20231027001", "items": [ { "cart_item_id": "ITEM_001", "product_id": 1001, "product_name": "测试商品A", "quantity": 1, "price": 99.99 } ] } } - 关键提取字段:
data.items[0].cart_item_id(用于后续下单,如果下单接口需要购物车项ID的话。有些接口下单时直接传product_id和sku_id,这里我们假设需要cart_item_id)。
3. 提交订单
- 端点:
POST {{base_url}}/api/v1/order/create - 请求头:需要认证
Authorization: Bearer {{access_token}}
- 请求体 (JSON):
{ "cart_item_ids": ["{{cart_item_id}}"], // 从购物车接口获取 "address_id": 1, // 使用一个测试地址ID "shipping_method": "express", "remark": "Postman场景测试订单" } - 成功响应 (JSON):
{ "code": 200, "message": "订单创建成功", "data": { "order_sn": "ORDER20231027123456", "total_amount": 99.99, "status": "待支付" } } - 关键提取字段:
data.order_sn
现在,我们明确了每个接口的输入输出,以及需要传递的关键数据:access_token,product_id,cart_item_id,order_sn。其中product_id我们可以先写死一个文档中提供的测试商品ID,比如1001。
4. 分步实现:编写请求与关联脚本
接下来,我们在之前创建的集合中,按顺序添加三个请求,并编写关键的关联脚本。
4.1 第一步:实现登录并提取Token
在“华测商城-核心场景测试”集合上右键,选择“Add request”。
命名为“01-用户登录”。
方法选择
POST,URL填写:{{base_url}}/api/v1/auth/login在“Body”标签页,选择
raw和JSON,粘贴登录请求体。关键步骤:编写Tests脚本提取token。 切换到“Tests”标签页。这里写的JavaScript代码会在请求发送后,响应返回时执行。我们的目的是从响应中拿到
access_token,并存入环境变量。// 1. 将响应体解析为JSON对象 const responseJson = pm.response.json(); // 2. 检查登录是否成功(根据接口规范判断) pm.test("登录接口状态码为200", function () { pm.response.to.have.status(200); }); pm.test("登录接口返回成功码", function () { pm.expect(responseJson.code).to.eql(200); }); // 3. 提取access_token并设置到环境变量中 if (responseJson.code === 200 && responseJson.data && responseJson.data.access_token) { const accessToken = responseJson.data.access_token; pm.environment.set("access_token", accessToken); console.log("Access Token已设置: ", accessToken); // 可以再做一个断言,确保token被正确设置(非必须,但有助于调试) pm.test("Access Token已成功存入环境变量", function () { pm.expect(pm.environment.get("access_token")).to.be.a('string').that.is.not.empty; }); } else { console.error("登录失败或响应格式异常: ", responseJson); // 可以在这里让测试失败 pm.test("登录响应中应包含有效的access_token", function () { pm.expect.fail("未能获取到有效的access_token"); }); }点击“Send”发送请求。如果成功,你会在“Test Results”面板看到通过的测试点,并且可以在右上角的环境快速查看器中,看到
access_token变量已经被更新为一长串Token字符串。
4.2 第二步:添加商品到购物车并提取Cart Item ID
- 在集合中新增请求,命名为“02-添加商品到购物车”。
- 方法
POST,URL:{{base_url}}/api/v1/cart/items - 在“Headers”标签页,添加一个Header:
- Key:
Authorization - Value:
Bearer {{access_token}}// 这里引用了上一步设置的环境变量
- Key:
- 在“Body”标签页,配置JSON请求体。注意,
product_id我们暂时写死为1001,你也可以先把它设置到环境变量product_id中,这里用{{product_id}}引用。{ "product_id": 1001, "sku_id": "SKU123456", "quantity": 1 } - 编写Tests脚本提取cart_item_id。
const responseJson = pm.response.json(); pm.test("加购接口状态码为200", function () { pm.response.to.have.status(200); }); pm.test("加购接口返回成功码", function () { pm.expect(responseJson.code).to.eql(200); }); // 提取购物车项ID。注意:实际响应结构可能不同,这里根据示例响应提取。 if (responseJson.code === 200 && responseJson.data && responseJson.data.items && responseJson.data.items.length > 0) { const cartItemId = responseJson.data.items[0].cart_item_id; pm.environment.set("cart_item_id", cartItemId); console.log("购物车项ID已设置: ", cartItemId); pm.test("购物车项ID已成功存入环境变量", function () { pm.expect(pm.environment.get("cart_item_id")).to.be.a('string').that.is.not.empty; }); } else { console.error("加购失败或购物车为空: ", responseJson); pm.test("加购响应应包含有效的购物车项", function () { pm.expect.fail("未能获取到有效的cart_item_id"); }); } - 发送请求。此时,Postman会自动使用第一步生成的
{{access_token}}作为Authorization头,并且请求成功后,会将cart_item_id存入环境变量。
4.3 第三步:提交订单并提取订单号
- 在集合中新增请求,命名为“03-提交订单”。
- 方法
POST,URL:{{base_url}}/api/v1/order/create - 在“Headers”标签页,同样添加
Authorization: Bearer {{access_token}}。 - 在“Body”标签页,配置JSON请求体。这里的关键是
cart_item_ids数组,我们使用上一步获取的{{cart_item_id}}。{ "cart_item_ids": ["{{cart_item_id}}"], "address_id": 1, "shipping_method": "express", "remark": "Postman场景测试订单" } - 编写Tests脚本提取订单号并清理环境(可选)。
const responseJson = pm.response.json(); pm.test("下单接口状态码为200或201", function () { pm.expect(pm.response.code).to.be.oneOf([200, 201]); // 创建成功常用201 }); pm.test("下单接口返回成功码", function () { pm.expect(responseJson.code).to.eql(200); }); // 提取订单号 if (responseJson.code === 200 && responseJson.data && responseJson.data.order_sn) { const orderSn = responseJson.data.order_sn; pm.environment.set("order_sn", orderSn); console.log("订单号已设置: ", orderSn); pm.test("订单创建成功,订单号有效", function () { pm.expect(orderSn).to.be.a('string').that.is.not.empty; pm.expect(orderSn).to.include('ORDER'); // 假设订单号包含ORDER前缀 }); // **【实操心得】场景测试后清理敏感数据** // 对于自动化测试集,跑完一个完整场景后,建议清理或重置环境变量,避免影响后续独立测试。 // 但如果是单次手动运行或演示,可以保留。这里我们选择注释掉清理代码,方便查看结果。 // console.log("【信息】场景执行完毕,如需清理,可取消下一行注释。"); // pm.environment.unset("access_token"); // pm.environment.unset("cart_item_id"); } else { console.error("下单失败: ", responseJson); } - 发送请求。至此,如果一切顺利,你将看到订单创建成功的响应,并且
order_sn也被记录到了环境变量中。
5. 一键运行与自动化:使用Collection Runner
单个请求调试通过后,真正的威力在于一键运行整个场景。
- 在Postman中,打开你的“华测商城-核心场景测试”集合。
- 点击集合名称旁边的“Run”按钮,会打开“Collection Runner”窗口。
- 在Runner界面:
- 确保右侧选择了正确的环境(
华测商城-测试环境)。 - 你可以看到集合内的三个请求按顺序排列。Runner会严格按照这个顺序执行。
- 可以设置迭代次数、延迟等,这里我们保持默认。
- 确保右侧选择了正确的环境(
- 点击蓝色的“Run 华测商城-核心场景测试”按钮。
Postman会依次执行“登录” -> “加购” -> “下单”三个请求。你会看到一个清晰的运行结果视图:
- 每个请求旁边会显示状态(Pass/Fail)和耗时。
- 点击每个请求,可以查看其请求详情和响应结果。
- 最关键的是,由于我们通过脚本设置了环境变量,后一个请求总能拿到前一个请求产生的最新数据,整个流程完全自动化。
这就是“逃课版”场景测试的完整实现。它不是一个全量的、严密的测试套件,但它用最小的代价,最快地验证了核心业务链路的通畅性。
6. 常见问题与高级技巧实录
在实际操作中,你几乎一定会遇到下面这些问题。我把它们和我的解决方案记录下来,希望能帮你少踩坑。
6.1 环境变量未生效或值为空
- 症状:请求发送时报错,或者
{{variable}}没有被替换,或者替换成了空值。 - 排查步骤:
- 检查环境是否激活:这是最常见的原因!务必确认Postman右上角下拉框选中的是你定义变量的那个环境。
- 检查变量名拼写:环境变量名、在URL/Header/Body里引用的变量名,必须完全一致,包括大小写。
{{access_token}}和{{Access_Token}}是两个变量。 - 检查脚本执行是否成功:在“Tests”脚本中多用
console.log()输出信息,在Postman控制台(View -> Show Postman Console)查看。确认pm.environment.set确实被执行了。 - 作用域问题:Postman有环境变量、集合变量、全局变量、局部变量(Data)等。确保你
set和get的是同一作用域的变量。我们这个例子用的都是环境变量。
6.2 接口响应结构变化导致提取失败
- 症状:脚本报错,提示
Cannot read property 'xxx' of undefined,或者提取的数据是undefined。 - 解决方案:
- 增强脚本健壮性:在提取数据前,增加多层判断。
// 不健壮的写法 const token = pm.response.json().data.access_token; // 健壮的写法 const response = pm.response.json(); let token; if (response && response.data && response.data.access_token) { token = response.data.access_token; } else { console.error("无法从响应中提取access_token,响应体为:", response); token = null; // 或抛出一个测试失败 } if (token) { pm.environment.set("access_token", token); } - 使用
pm.expect进行防御性断言:在Tests中先对响应结构进行断言,提前失败,便于定位。pm.test("响应包含data字段", function() { pm.expect(response).to.have.property('data'); }); pm.test("data字段包含access_token", function() { pm.expect(response.data).to.have.property('access_token'); });
- 增强脚本健壮性:在提取数据前,增加多层判断。
6.3 依赖接口失败导致后续请求无意义
- 症状:登录失败了,但Postman Collection Runner还是会继续执行后面的加购、下单请求,显然这些请求都会因为缺乏token而失败,产生大量无效报错。
- 高级技巧:使用
postman.setNextRequest(null)中断流程。 你可以在某个关键请求(如登录)的Tests脚本中,如果判断失败,就中止整个集合的运行。// 在“01-用户登录”的Tests脚本末尾,如果登录失败 if (responseJson.code !== 200) { console.error("登录失败,中止后续流程"); postman.setNextRequest(null); // 将下一个请求设置为null,Collection Runner就会停止 // 或者可以跳转到某个特定的清理请求 // postman.setNextRequest("99-清理环境"); }
6.4 处理动态数据,如商品ID
- 问题:我们之前把
product_id写死了。在实际测试中,可能需要先调用商品列表接口,获取一个有效的、在售的商品ID。 - 解决方案:在“登录”请求之后,“加购”请求之前,插入一个“获取商品列表”的请求。
- 新增一个请求“01.5-获取商品列表”,方法为
GET,URL如{{base_url}}/api/v1/products?page=1&size=1。 - 在其Tests脚本中,从响应中提取第一个商品的ID,并设置到环境变量
product_id中。const products = pm.response.json().data.list; // 假设响应结构如此 if (products && products.length > 0) { pm.environment.set("product_id", products[0].id); console.log("设置商品ID为: ", products[0].id); } - 在“02-添加商品到购物车”的请求体中,将
product_id的值改为{{product_id}}。 - 在Collection Runner中调整请求顺序为:01 -> 01.5 -> 02 -> 03。
- 新增一个请求“01.5-获取商品列表”,方法为
6.5 使用Pre-request Script处理动态参数
- 场景:有些接口需要时间戳、随机数或加密签名作为参数。
- 示例:为请求添加一个时间戳
timestamp和随机数nonce。 在请求的“Pre-request Script”标签页(在请求发送前执行)编写:
然后在请求的URL或Body中,就可以使用// 生成13位时间戳 const timestamp = new Date().getTime(); pm.environment.set("current_timestamp", timestamp); // 生成一个随机字符串作为nonce const nonce = Math.random().toString(36).substring(2, 15); pm.environment.set("current_nonce", nonce);{{current_timestamp}}和{{current_nonce}}来引用了。
通过以上步骤和技巧,你已经掌握了使用Postman进行接口关联测试的核心方法。这种“逃课版”的场景串联,能让你在复杂的接口网络中迅速找到一条可通行的路径,极大地提升接口调试和业务流程验证的效率。记住,工具是死的,人是活的,关键在于理解数据如何流动,并让工具帮你自动化这个流动的过程。
