测试门控
CI 中跑单元、集成和 e2e 测试作失败阻合门控、带覆阈值。
为什么
测试是最重要质量门控——是代码的可执行规约、抓无其他门控能抓的回归。测试门控在 CI 跑测试套件任何测试失败阻合、意味回归无测试先失败不能到生产。测试门控有三层: 单元测试(快、测逻辑、每 PR 跑)、集成测试(中、测 API 和 DB、每 PR 跑)和 e2e 测试(慢、测用户流、每 PR 或仅 main 跑)。每层抓不同类 bug、一起提供改不破现有行为信心。覆 阈值(如 80% 行覆)确保新代码被测——无它开发者可加未测代码门控仍过。测试门控非好测试替代(断言 toBeDefined() 过门控但抓无)但是防最坏回归发的地板。
何时使用
每 PR——单元和集成测试每 PR、e2e 每 PR(或至少 main)、强覆阈值。
如何做
1. 每 PR 跑单元测试(快、1-5 分钟)
- npm test(jest、pytest、cargo test)
- 可能时仅跑受影响测试(jest --findRelatedTests)
- 任何测试失败构建失败
- 这是最重要门控——抓逻辑回归
2. 每 PR 跑集成测试(中、5-10 分钟)
- 用真或测试数据库测 API 端点
- 用真或测试数据库测 DB 查询
- 用测试数据库(非生产)——CI 中起、后拆
- 任何集成测试失败构建失败
3. 每 PR 或 main 跑 e2e 测试(慢、10-30 分钟)
- 测关键用户流(登录、结账、搜索)
- 用 Playwright、Cypress 或 Selenium
- 够快则每 PR 跑、太慢则仅 main
- 任何 e2e 测试失败构建失败
4. 强覆阈值
- jest --coverage --coverageThreshold='{"global":{"lines":80}}'
- 覆降阈值下构建失败
- 这确保新代码被测
- 勿设阈值太高(100% 反生产)
5. 并行测试
- jest --maxWorkers=4(4 测试文件并行)
- e2e 测试跨多运行器分
- 这减门控时间从 20 分钟到 5 分钟
6. 清报结果
- 显哪些测试失败、带错误消息和栈迹
- 显覆报告(哪些行未覆)
- 用与 GitHub 集成的测试报告器(PR 上标注)示例
# .github/workflows/ci.yml — 测试门控
name: CI
on: [pull_request]
jobs:
# 门控 1: 单元测试(2 分)——快、每 PR 跑
unit-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm test -- --coverage --maxWorkers=4
env:
COVERAGE_THRESHOLD: '{"global":{"lines":80,"branches":70}}'
# 门控 2: 集成测试(5 分)——中、每 PR 跑
integration-test:
needs: [unit-test] # 等单元测试过
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15
env:
POSTGRES_PASSWORD: test
ports: ['5432:5432']
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run test:integration
# 门控 3: E2E 测试(15 分)——慢、每 PR 跑
e2e-test:
needs: [integration-test] # 等集成测试
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run build
- run: npx playwright test
- uses: actions/upload-artifact@v4
if: always() # 即使失败也传截图
with:
name: playwright-report
path: playwright-report/
# package.json — 测试脚本
{
"scripts": {
"test": "jest", // 单元测试
"test:integration": "jest --config jest.integration.config.js",
"test:e2e": "playwright test"
}
}
# jest.config.js — 覆阈值
{
"coverageThreshold": {
"global": {
"lines": 80,
"branches": 70,
"functions": 80,
"statements": 80
}
}
}
# 分支保护: 要求所有测试门控
# 设置 > 分支 > 分支保护规则:
# - 要求状态检查: unit-test、integration-test、e2e-test
# - 不允许绕
# PR 上测试失败标注(GitHub)
# 测试报告器在 PR 上显失败测试为标注:
# ❌ test/user.test.ts > getUser > 返回匹配 id 的用户
# 期望: { id: 1, name: "Alice" }
# 收到: { id: 1, name: null }
# at Object.<anonymous> (test/user.test.ts:15:23)常见问题
- ⚠覆阈值设 100%——开发者花时间为琐碎 getter 和 setter 写测试达阈值、测试无价值但慢套件和审查。
- ⚠每 PR 跑 30 分钟 e2e——开发者等 30 分钟反馈、管道感慢、团队开始绕 e2e 门控解阻 PR。
- ⚠集成测试不起测试数据库——测试跑开发者数据库或共享数据库、测试不稳(PR 间数据冲突)、门控不可靠。
- ⚠覆降不失败构建——覆从 80% 降到 60% 随未测代码加、门控仍过(无阈值)、代码库累积未测代码。
最佳实践
- ✓单元测试(快、每 PR)、集成测试(中、每 PR 带测试数据库)和 e2e 测试(慢、每 PR 或 main)作分门控、从快到慢排带 needs: 依赖。
- ✓强覆阈值(80% 行、70% 分支 )降时构建失败——这确保新代码被测但勿设 100%(反生产浪费时间于琐碎测试)。
- ✓并行测试(jest --maxWorkers=4、e2e 跨运行器分)可能时仅跑受影响测试——这减门控时间从 20 分钟到 5 分钟。
- ✓CI 中为集成测试起新测试数据库(非共享)失败时传产物(截图、报告)——这使测试可靠失败可调试。