Skip to content
返回质量保障

测试门控

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 中为集成测试起新测试数据库(非共享)失败时传产物(截图、报告)——这使测试可靠失败可调试。