跳到主要内容

自动化测试集成策略

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 框架选择

框架特点
VitestVite 生态,快
Jest生态最大
node:testNode 内置,轻量

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:反馈慢、定位难
  • 测试互相依赖(共享状态):并行跑必挂
  • 失败截图不上传:排查无线索

10. 延伸阅读