⚠️ Alpha内测版本警告:此为早期内部构建版本,尚不完整且可能存在错误,欢迎大家提Issue反馈问题或建议
Skip to content

9.5.4 测试覆盖了多少代码——测试覆盖率:代码覆盖率阈值设置

覆盖率不是目标,而是指标——80% 的覆盖率比 100% 的虚假覆盖更有价值。

覆盖率类型

Jest 覆盖率配置

typescript
// jest.config.ts
import type { Config } from 'jest';

const config: Config = {
  collectCoverage: true,
  coverageDirectory: 'coverage',
  coverageProvider: 'v8',
  
  collectCoverageFrom: [
    'src/**/*.{ts,tsx}',
    '!src/**/*.d.ts',
    '!src/**/*.test.{ts,tsx}',
    '!src/**/*.stories.{ts,tsx}',
    '!src/types/**/*',
  ],
  
  coverageThreshold: {
    global: {
      branches: 80,
      functions: 80,
      lines: 80,
      statements: 80,
    },
    // 关键模块更高要求
    './src/services/': {
      branches: 90,
      functions: 90,
      lines: 90,
      statements: 90,
    },
  },
  
  coverageReporters: ['text', 'lcov', 'html'],
};

export default config;

CI 配置

yaml
# .github/workflows/ci.yml
jobs:
  test:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v4
      
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      
      - run: npm ci
      
      - name: Run tests with coverage
        run: npm run test:ci
      
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v3
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          files: ./coverage/lcov.info
          fail_ci_if_error: true
          verbose: true

package.json 脚本

json
{
  "scripts": {
    "test": "jest",
    "test:ci": "jest --ci --coverage --maxWorkers=2",
    "test:coverage": "jest --coverage --coverageReporters=text"
  }
}

Codecov 配置

yaml
# codecov.yml
coverage:
  status:
    project:
      default:
        target: 80%
        threshold: 2%
    patch:
      default:
        target: 80%

comment:
  layout: "reach,diff,flags,tree"
  behavior: default
  require_changes: true

ignore:
  - "**/*.test.ts"
  - "**/*.d.ts"
  - "src/types/**"

合理的覆盖率目标

代码类型建议覆盖率原因
业务服务90%+核心逻辑必须充分测试
API 路由80%+接口契约需要验证
工具函数95%+纯函数容易测试
UI 组件60-70%视觉测试更重要
配置文件忽略无需测试

避免虚假覆盖

typescript
// ❌ 虚假覆盖:只调用不验证
it('should create user', async () => {
  await userService.create({ email: 'test@example.com' });
  // 没有断言,覆盖率高但没价值
});

// ✅ 真实覆盖:验证行为
it('should create user with hashed password', async () => {
  const user = await userService.create({
    email: 'test@example.com',
    password: 'secret',
  });
  
  expect(user.email).toBe('test@example.com');
  expect(user.password).not.toBe('secret');
  expect(await bcrypt.compare('secret', user.password)).toBe(true);
});

覆盖率报告分析

bash
# 查看覆盖率报告
npm run test:coverage

# 打开 HTML 报告
open coverage/lcov-report/index.html
-------------------|---------|----------|---------|---------|
File               | % Stmts | % Branch | % Funcs | % Lines |
-------------------|---------|----------|---------|---------|
All files          |   85.23 |    78.45 |   82.14 |   85.67 |
 services/         |   92.45 |    88.23 |   90.12 |   92.78 |
  user.service.ts  |   95.12 |    92.34 |   94.56 |   95.45 |
  order.service.ts |   89.78 |    84.12 |   85.67 |   90.12 |
 lib/              |   78.34 |    68.45 |   74.23 |   78.89 |
-------------------|---------|----------|---------|---------|

渐进式提升

yaml
# codecov.yml
coverage:
  status:
    project:
      default:
        # 只要求不降低覆盖率
        target: auto
        threshold: 1%
    patch:
      default:
        # 新代码必须 80% 覆盖
        target: 80%

本节小结

覆盖率是代码质量的参考指标,不是目标。设置合理的阈值(80% 是常见选择),关注新增代码的覆盖率,避免虚假覆盖。使用 Codecov 集成到 PR 流程,让覆盖率变化可视化。