用 Postman 做数据驱动测试:把一批测试用例写进 CSV(中文、引号、空格、空值、超长……),同一个请求自动跑 6 遍,每遍用一行数据并检查期望的状态码。同时写一个集合级脚本,令牌没有或快过期时自动重新登录,不用手动复制粘贴令牌。
先看清成品
成品是一个集合加一个
cases.csv。本文已用 Newman 6.2.3 对本地练习 API 实际运行:6 次迭代、12 条断言全部通过;正常令牌有效期下整个运行只登录 1 次;把令牌有效期调到 6 秒、请求间隔 1.5 秒时,脚本在令牌快过期时自动重新登录。在 Postman 桌面应用里的操作没有截图验证。
注意:只对你自己的或者明确允许测试的 API 运行自动化测试。
做完之后你会得到什么?
| 成果 | 说明 |
|---|---|
| 用例文件 | cases.csv,加用例不用改脚本 |
| 自动登录 | 集合级预请求脚本 + pm.sendRequest |
| 安全拼请求体 | 标题先 JSON.stringify,引号不会破坏 JSON |
| 按行断言 | 期望值来自数据文件 |
需要准备哪些环境?
| 项目 | 要求 | 说明 |
|---|---|---|
| Postman 桌面应用 | 免费账号即可 | 官网下载,各计划限制以价格页为准 |
| Node.js | 18 或更高 | 运行练习 API,本文使用 22.23.3 |
| 练习 API | 本文提供的 server.js |
不依赖任何第三方包 |
| Newman | npm i -g newman |
本文使用 6.2.3 |
练习 API 和环境变量(baseUrl、username、password)与本系列 Postman 教程 A 相同,server.js 在本文的 -src 文件夹里。它支持用 TOKEN_TTL_MS 环境变量调整令牌有效期,方便测试自动登录。
第一步:用例文件怎么写?
case,title,expectStatus
普通中文,买牛奶,201
带引号,"他说""你好""",201
首尾空格, 跑步 5 公里 ,201
空字符串,,400
只有空格, ,400
超过100字,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,400
| 要点 | 说明 |
|---|---|
| 第一行是列名 | 脚本里用 pm.iterationData.get('列名') 读取 |
| 含引号的值 | CSV 规则:整格用双引号包起来,内部引号写两次 |
| 首尾空格 | 保留在数据里,用来测试接口会不会去掉空格 |
第二步:脚本怎么写?
1. 集合级预请求脚本(自动登录)
在集合的 Scripts → Pre-request 粘贴:
// 集合级预请求脚本:没有令牌或快过期时,自动登录换新令牌
const exp = Number(pm.collectionVariables.get('tokenExp') || 0);
if (pm.collectionVariables.get('token') && Date.now() < exp - 5000) return;
pm.sendRequest({
url: pm.environment.get('baseUrl') + '/login',
method: 'POST',
header: { 'Content-Type': 'application/json' },
body: { mode: 'raw', raw: JSON.stringify({ username: pm.environment.get('username'), password: pm.environment.get('password') }) }
}, (err, res) => {
if (err || res.code !== 200) throw new Error('自动登录失败:' + (err || res.code));
const j = res.json();
pm.collectionVariables.set('token', j.token);
pm.collectionVariables.set('tokenExp', Date.now() + j.expires_in * 1000);
pm.collectionVariables.set('loginCount', Number(pm.collectionVariables.get('loginCount') || 0) + 1);
console.log('已自动登录,第 ' + pm.collectionVariables.get('loginCount') + ' 次');
});
集合 Authorization 选 Bearer Token,值 {{token}};Variables 添加 token、tokenExp、loginCount。
集合级脚本会在集合里每个请求之前执行,所以令牌快过期时总能及时换新。提前 5 秒刷新,避免请求发出去时刚好过期。
2. 请求:新建待办(数据驱动)
POST {{baseUrl}}/todos,Body 选 raw JSON:
{"title": {{titleJson}}}
注意 {{titleJson}} 外面没有引号。请求自己的 Pre-request:
// 把数据行里的标题转成 JSON 字符串,避免引号、换行破坏请求体
pm.variables.set('titleJson', JSON.stringify(String(pm.iterationData.get('title') ?? '')));
Post-response:
// 期望值来自数据文件的当前行
const expected = Number(pm.iterationData.get('expectStatus'));
pm.test(`「${pm.iterationData.get('case')}」状态码应为 ${expected}`, () => pm.response.to.have.status(expected));
if (expected === 201) {
pm.test('标题被去掉首尾空格后保存', () => pm.expect(pm.response.json().title).to.eql(String(pm.iterationData.get('title')).trim()));
} else {
pm.test('返回错误信息', () => pm.expect(pm.response.json()).to.have.property('error'));
}
第三步:怎样运行?
1. 在应用里
集合 Run collection,在 Data 处选择 cases.csv,迭代次数会自动变成 6,点 Run。
2. 用 Newman
node server.js &
newman run todo-data.postman_collection.json -e local.postman_environment.json -d cases.csv
本文实际输出(节选):
│ '已自动登录,第 1 次'
✓ 「普通中文」状态码应为 201
✓ 标题被去掉首尾空格后保存
✓ 「带引号」状态码应为 201
...
✓ 「超过100字」状态码应为 400
✓ 返回错误信息
│ iterations │ 6 │ 0 │
│ assertions │ 12 │ 0 │
3. 验证自动续期
TOKEN_TTL_MS=6000 node server.js &
newman run todo-data.postman_collection.json -e local.postman_environment.json -d cases.csv --delay-request 1500
令牌只剩 6 秒有效期,脚本提前 5 秒刷新,所以本文实测每次迭代前都自动重新登录了一次,断言仍然全部通过。
出问题时该怎么调?
1. 请求体 JSON 解析失败
最常见的原因是写成了 "title": "{{title}}",遇到带引号的用例就坏了。改用本文的 titleJson 写法。
2. 自动登录报错“自动登录失败:401”
环境里的用户名密码错误,或者没有选中环境。
3. 空值那一行读到的是 undefined
CSV 中空格子读出来可能是空字符串,也可能缺失。脚本里用 ?? '' 统一成空字符串。
常见问题怎么处理?
| 现象 | 原因 | 解决方法 |
|---|---|---|
| 迭代只跑了 1 次 | 没选数据文件 | 选 cases.csv 或加 -d |
| 数字列读成字符串 | CSV 都是文本 | 用 Number() 转换 |
| 想用 JSON 数据文件 | CSV 不好表达嵌套 | 数据文件也支持 JSON 数组 |
| 每个请求都在重新登录 | 有效期判断错误 | 检查 tokenExp 是否存成了毫秒 |
| 测试数据越积越多 | 只新建不删除 | 测试结束加一个清理请求 |
项目资源
建议先用默认有效期跑通 6 个用例,然后加两行你能想到的刁钻输入(例如 emoji、换行)看看接口是否扛得住。
最后用 TOKEN_TTL_MS 把有效期调短,亲眼确认自动登录生效,再把这套脚本搬到真实项目。