把 Postman 集合接进 GitHub Actions:每次推送、每个拉取请求、以及每天定时,自动启动被测 API,用 Postman CLI 运行集合,有任何断言失败就让流水线变红,并把 JUnit 测试报告和服务日志存成构建产物。密码放在 GitHub Secrets 里,不进仓库。
先看清成品
成品是
.github/workflows/api-tests.yml。本文已实际验证:actionlint 1.7.12 检查工作流文件无错误;在本机用 Postman CLI 1.75.0 运行同样的命令,通过--env-var传入正确密码时退出码 0 并生成results/junit.xml,传入错误密码时断言失败、退出码 1(流水线会因此失败)。本文环境没有 GitHub 仓库,工作流没有在 GitHub 上实际运行。
注意:工作流日志对有仓库访问权限的人可见。不要在脚本里
console.log令牌或密码。
做完之后你会得到什么?
| 成果 | 说明 |
|---|---|
| 自动触发 | 推送 main、拉取请求、每天、手动 |
| 被测服务 | 在流水线里启动并等待就绪 |
| 失败即红 | Postman CLI 断言失败返回非 0 |
| 测试报告 | JUnit XML + 服务日志 |
| 密钥管理 | GitHub Secrets 注入密码 |
需要准备哪些环境?
| 项目 | 要求 | 说明 |
|---|---|---|
| GitHub 仓库 | 公开或私有 | 私有仓库的 Actions 分钟数有限额 |
| Postman 集合 | 导出为 v2.1 JSON | 本文沿用教程 A 的集合 |
| Postman CLI | 本地调试用 | 官方安装:curl -o- "https://dl-cli.pstmn.io/install/unix.sh" | sh |
第一步:仓库结构是什么样的?
todo-api/
├── server.js # 被测 API
├── package.json
├── postman/
│ ├── todo-api.postman_collection.json # 从 Postman 导出
│ └── ci.postman_environment.json # 不含密码
└── .github/workflows/api-tests.yml
在 Postman 里导出集合:集合 ⋯ → Export,选 Collection v2.1。
第二步:文件怎么写?
1. ci.postman_environment.json
{
"name": "ci",
"values": [
{ "key": "baseUrl", "value": "http://localhost:3000", "enabled": true },
{ "key": "username", "value": "alice", "enabled": true },
{ "key": "password", "value": "", "enabled": true, "type": "secret" }
]
}
密码留空,运行时用 --env-var 覆盖。
2. api-tests.yml
name: API 测试
on:
push:
branches: [main]
pull_request:
schedule:
- cron: '0 1 * * *' # 每天 UTC 1 点(北京时间 9 点)
workflow_dispatch:
jobs:
postman:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- name: 启动被测 API
run: |
node server.js > server.log 2>&1 &
for i in $(seq 1 20); do
curl -s -o /dev/null http://localhost:3000/todos && break
sleep 1
done
- name: 安装 Postman CLI
run: curl -o- "https://dl-cli.pstmn.io/install/unix.sh" | sh
- name: 运行集合
run: |
postman collection run postman/todo-api.postman_collection.json \
-e postman/ci.postman_environment.json \
--env-var "password=${{ secrets.API_PASSWORD }}" \
-r cli,junit --reporter-junit-export results/junit.xml
- name: 上传测试报告
if: always()
uses: actions/upload-artifact@v4
with:
name: postman-results
path: |
results/
server.log
| 要点 | 说明 |
|---|---|
| 等待就绪循环 | 服务没起来就跑测试会全部失败 |
--env-var |
用 Secrets 覆盖环境里的空密码 |
-r cli,junit |
终端输出加 JUnit 报告 |
if: always() |
测试失败时也上传报告,方便排查 |
timeout-minutes |
防止卡住白白消耗分钟数 |
3. 添加 Secret
仓库 Settings → Secrets and variables → Actions → New repository secret,名称 API_PASSWORD,值为 pass123(练习 API 的密码)。
第三步:怎样验证?
1. 本地先跑同样的命令
node server.js &
postman collection run postman/todo-api.postman_collection.json \
-e postman/ci.postman_environment.json \
--env-var "password=pass123" \
-r cli,junit --reporter-junit-export results/junit.xml
echo $?
本文实际:退出码 0,生成 results/junit.xml。把密码改成 wrong 再跑,本文实际输出:
01. AssertionError 状态码 200
02. AssertionError 返回 token
退出码 1。
2. 推送到 GitHub
git add . && git commit -m "add api tests" && git push
到仓库 Actions 标签查看,期望“API 测试”显示绿色对勾。运行详情页底部 Artifacts 可以下载 postman-results。
3. 故意弄坏一次
把 server.js 里新建待办的状态码 201 改成 200,开一个拉取请求,确认流水线变红,拉取请求页面显示检查失败。
出问题时该怎么调?
1. 全部请求 ECONNREFUSED
服务没启动成功。下载产物里的 server.log 查看报错。
2. 第一个请求就 401
Secret 名称和工作流里写的不一致,或者是从 fork 发起的拉取请求(GitHub 默认不给 fork 的拉取请求传 Secrets)。
3. 安装 Postman CLI 失败
偶发网络问题时重跑。也可以改用 Newman:
- run: npx newman@6 run postman/todo-api.postman_collection.json -e postman/ci.postman_environment.json --env-var "password=${{ secrets.API_PASSWORD }}" -r cli,junit --reporter-junit-export results/junit.xml
常见问题怎么处理?
| 现象 | 原因 | 解决方法 |
|---|---|---|
| 定时任务时间不对 | cron 按 UTC | 北京时间减 8 小时 |
| 定时任务停了 | 仓库长期无活动时 GitHub 会停用定时工作流 | 到 Actions 页面重新启用 |
| 集合改了 CI 没变 | 忘了重新导出 | 每次改完重新导出提交 |
| 想测线上环境 | baseUrl 是 localhost |
另建环境文件,地址放 Secret |
| 报告想直接显示在页面 | 只上传了文件 | 可以用第三方 JUnit 展示 Action |
项目资源
| 用途 | 地址 |
|---|---|
| Postman CLI 安装 | https://learning.postman.com/docs/postman-cli/postman-cli-installation/ |
| Postman CLI 运行集合 | https://learning.postman.com/docs/postman-cli/postman-cli-run-collection/ |
| Newman | https://github.com/postmanlabs/newman |
| 测试脚本写法 | https://learning.postman.com/docs/tests-and-scripts/write-scripts/test-scripts/ |
| GitHub Actions 文档 | https://docs.github.com/actions |
| actionlint | https://github.com/rhysd/actionlint |
建议先在本地用同样的命令跑通,确认退出码在成功和失败时分别是 0 和 1,再推送工作流。
流水线变绿后,故意改坏一次接口,确认它真的会拦住有问题的拉取请求。