自动化测试集成策略
1. 测试金字塔
/ E2E \ 慢、贵、少
/─────────\
/ Integration\ 中间层
/───────────────\
/ Unit Tests \ 快、便宜、多
/─────────────────────\
前端 CI 里三层都要跑,按成本和反馈速度分配比例。
2. CI 测试流水线
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20, cache: npm }
- run: npm ci
- run: npm run lint
- run: npx tsc --noEmit # TypeScript 类型检查
unit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20, cache: npm }
- run: npm ci
- run: npm run test -- --coverage --ci
- name: Coverage threshold
run: |
npx istanbul check-coverage --lines 80 --functions 80 --branches 70
e2e:
runs-on: ubuntu-latest
needs: [lint, unit]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20, cache: npm }
- run: npm ci
- run: npx playwright install --with-deps
- run: npm run build
- run: npm run test:e2e
- uses: actions/upload-artifact@v4
if: failure()
with:
name: playwright-report
path: playwright-report/
3. Lint 与格式
# ESLint
npx eslint . --max-warnings 0
# Prettier 检查(不修改)
npx prettier --check .
# TypeScript
npx tsc --noEmit
# Stylelint
npx stylelint "**/*.css"
CI 里 --max-warnings 0 强制 0 警告,避免逐步腐化。
3.1 lint-staged + husky(本地)
// package.json
{
"lint-staged": {
"*.{ts,tsx}": ["eslint --fix", "prettier --write"],
"*.css": ["stylelint --fix"]
}
}
commit 前跑 lint,CI 是兜底。
4. 单元测试
4.1 框架选择
| 框架 | 特点 |
|---|---|
| Vitest | Vite 生态,快 |
| Jest | 生态最大 |
| node:test | Node 内置,轻量 |
4.2 覆盖率门禁
// vitest.config.ts
{
test: {
coverage: {
provider: 'v8',
reporter: ['text', 'lcov', 'json-summary'],
thresholds: {
lines: 80,
functions: 80,
branches: 70,
statements: 80
}
}
}
}
CI 里加 --coverage,低于阈值直接失败。
4.3 CI 报告
- name: Test Report
uses: dorny/test-reporter@v1
if: always()
with:
name: Unit Tests
path: junit.xml
reporter: jest-junit
PR 里直接看测试结果。
5. E2E 测试
5.1 Playwright(推荐)
// tests/login.spec.ts
import { test, expect } from '@playwright/test'
test('login flow', async ({ page }) => {
await page.goto('/login')
await page.fill('[name="email"]', 'test@example.com')
await page.fill('[name="password"]', 'password')
await page.click('button[type="submit"]')
await expect(page).toHaveURL('/dashboard')
await expect(page.locator('h1')).toContainText('Welcome')
})
5.2 CI 配置
- run: npx playwright install --with-deps
- run: npm run build && npm run start &
- run: npx playwright test
env:
BASE_URL: http://localhost:3000
5.3 视觉回归
await expect(page).toHaveScreenshot('dashboard.png', {
maxDiffPixels: 100,
})
截图存 git(或 S3),变化时 PR 里对比。
5.4 并行与分片
strategy:
matrix:
shard: [1/4, 2/4, 3/4, 4/4]
steps:
- run: npx playwright test --shard=$}} matrix.shard }}
6. 集成测试
API 集成测试用真实依赖(docker-compose):
services:
test:
build: .
depends_on: [db, redis]
command: npm run test:integration
db:
image: postgres:16-alpine
environment:
POSTGRES_PASSWORD: test
redis:
image: redis:7-alpine
# CI
- run: docker compose -f docker-compose.test.yml up --exit-code-from test
7. PR 预览 + 测试
Vercel / Netlify 自动给 PR 部署预览 URL。E2E 对预览 URL 跑:
- name: Wait for preview
uses: patrickedqvist/wait-for-vercel-preview@v1.3.1
with:
token: $}} secrets.GITHUB_TOKEN }}
max_timeout: 300
id: preview
- run: npx playwright test
env:
BASE_URL: $}} steps.preview.outputs.url }}
8. 测试策略选型
| 场景 | 推荐 |
|---|---|
| 纯函数 / hooks | 单元测试(Vitest) |
| 组件交互 | 组件测试(Testing Library) |
| 页面流程 | E2E(Playwright) |
| API 契约 | 集成测试 / Contract test |
| 视觉 | 截图对比(Playwright / Chromatic) |
| 性能 | Lighthouse CI + size-limit |
9. 常见反模式
- CI 不跑测试:代码质量靠人肉
- 测试太慢跳过:应该并行 / 分片
- E2E 用 sleep 等待:应该用
waitFor/expect.toBeVisible - 测试依赖外部服务:mock 或 docker 固定环境
- 覆盖率 100% 执念:追求有效覆盖而非数字
- 只有 E2E 没有 Unit:反馈慢、定位难
- 测试互相依赖(共享状态):并行跑必挂
- 失败截图不上传:排查无线索