Skip to content

Bun 的测试运行器现在支持内置代码覆盖率报告。这使得查看代码库中有多少被测试覆盖以及查找当前未得到充分测试的区域变得容易。

启用覆盖率

bun:test 支持查看哪些代码行被测试覆盖。要使用此功能,请在 CLI 中传递 --coverage。它将在控制台打印覆盖率报告:

bash
bun test --coverage

-------------|---------|---------|-------------------
File         | % Funcs | % Lines | Uncovered Line #s
-------------|---------|---------|-------------------
All files    |   38.89 |   42.11 |
 index-0.ts  |   33.33 |   36.84 | 10-15,19-24
 index-1.ts  |   33.33 |   36.84 | 10-15,19-24
 index-10.ts |   33.33 |   36.84 | 10-15,19-24
 index-2.ts  |   33.33 |   36.84 | 10-15,19-24
 index-3.ts  |   33.33 |   36.84 | 10-15,19-24
 index-4.ts  |   33.33 |   36.84 | 10-15,19-24
 index-5.ts  |   33.33 |   36.84 | 10-15,19-24
 index-6.ts  |   33.33 |   36.84 | 10-15,19-24
 index-7.ts  |   33.33 |   36.84 | 10-15,19-24
 index-8.ts  |   33.33 |   36.84 | 10-15,19-24
 index-9.ts  |   33.33 |   36.84 | 10-15,19-24
 index.ts    |  100.00 |  100.00 |
-------------|---------|---------|-------------------

默认启用

要始终默认启用覆盖率报告,请在 bunfig.toml 中添加以下行:

toml
[test]
# 始终启用覆盖率
coverage = true

默认情况下,覆盖率报告将包含测试文件并排除 sourcemaps。这通常是你想要的,但也可以在 bunfig.toml 中进行配置。

toml
[test]
coverageSkipTestFiles = true  # 默认 false

覆盖率阈值

可以在 bunfig.toml 中指定覆盖率阈值。如果你的测试套件未达到或超过此阈值,bun test 将以非零退出码退出以指示失败。

简单阈值

toml
[test]
# 要求 90% 的行级和函数级覆盖率
coverageThreshold = 0.9

详细阈值

toml
[test]
# 为行和函数设置不同的阈值
coverageThreshold = { lines = 0.9, functions = 0.9, statements = 0.9 }

设置任何这些阈值将启用 fail_on_low_coverage,如果覆盖率低于阈值,测试运行将失败。

覆盖率报告器

默认情况下,覆盖率报告将打印到控制台。

对于 CI 环境和其他工具中的持久代码覆盖率报告,你可以传递 --coverage-reporter=lcov CLI 选项或在 bunfig.toml 中使用 coverageReporter 选项。

toml
[test]
coverageReporter = ["text", "lcov"]  # 默认 ["text"]
coverageDir = "path/to/somewhere"    # 默认 "coverage"

可用的报告器

报告器描述
text在控制台打印覆盖率的文本摘要
lcov以 lcov 格式保存覆盖率

LCOV 覆盖率报告器

要生成 lcov 报告,你可以使用 lcov 报告器。这将在 coverage 目录中生成一个 lcov.info 文件。

toml
[test]
coverageReporter = "lcov"
bash
# 或通过 CLI
bun test --coverage --coverage-reporter=lcov

LCOV 格式被各种工具和服务广泛支持:

  • 代码编辑器:VS Code 扩展可以内联显示覆盖率
  • CI/CD 服务:GitHub Actions、GitLab CI、CircleCI
  • 覆盖率服务:Codecov、Coveralls
  • IDE:WebStorm、IntelliJ IDEA

在 GitHub Actions 中使用 LCOV

yaml
name: Test with Coverage
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: oven-sh/setup-bun@v2
      - run: bun install
      - run: bun test --coverage --coverage-reporter=lcov
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v3
        with:
          file: ./coverage/lcov.info

从覆盖率中排除文件

跳过测试文件

默认情况下,测试文件本身包含在覆盖率报告中。你可以使用以下方法排除它们:

toml
[test]
coverageSkipTestFiles = true  # 默认 false

这将排除与测试模式匹配的文件(例如 *.test.ts*.spec.js)不显示在覆盖率报告中。

忽略特定路径和模式

你可以使用 coveragePathIgnorePatterns 从覆盖率报告中排除特定文件或文件模式:

toml
[test]
# 单个模式
coveragePathIgnorePatterns = "**/*.spec.ts"

# 多个模式
coveragePathIgnorePatterns = [
  "**/*.spec.ts",
  "**/*.test.ts",
  "src/utils/**",
  "*.config.js"
]

此选项接受 glob 模式,工作方式类似于 Jest 的 collectCoverageFrom 忽略模式。与任何这些模式匹配的文件将从文本和 LCOV 输出中的覆盖率计算和报告中排除。

常见用例

toml
[test]
coveragePathIgnorePatterns = [
  # 排除工具文件
  "src/utils/**",

  # 排除配置文件
  "*.config.js",
  "webpack.config.ts",
  "vite.config.ts",

  # 排除特定测试模式
  "**/*.spec.ts",
  "**/*.e2e.ts",

  # 排除构建产物
  "dist/**",
  "build/**",

  # 排除生成的文件
  "src/generated/**",
  "**/*.generated.ts",

  # 排除供应商/第三方代码
  "vendor/**",
  "third-party/**"
]

Sourcemaps

在内部,Bun 默认转译所有文件,因此 Bun 会自动生成一个内部 source map,将原始源代码的行映射到 Bun 的内部表示。如果由于任何原因你想禁用此功能,请将 test.coverageIgnoreSourcemaps 设置为 true;这在高级用例之外很少需要。

toml
[test]
coverageIgnoreSourcemaps = true  # 默认 false

覆盖率默认值

默认情况下,覆盖率报告:

  • 排除 node_modules 目录
  • 排除 通过非 JS/TS 加载器加载的文件(例如 .css.txt),除非指定了自定义 JS 加载器
  • 包含 测试文件本身(可以使用 coverageSkipTestFiles = true 禁用)
  • 可以使用 coveragePathIgnorePatterns 排除其他文件

高级配置

自定义覆盖率目录

toml
[test]
coverageDir = "coverage-reports"  # 默认 "coverage"

多个报告器

toml
[test]
coverageReporter = ["text", "lcov"]

使用特定测试模式的覆盖率

bash
# 仅对特定测试文件运行覆盖率
bun test --coverage src/components/*.test.ts

# 使用名称模式运行覆盖率
bun test --coverage --test-name-pattern="API"

CI/CD 集成

GitHub Actions 示例

yaml
name: Coverage Report
on: [push, pull_request]

jobs:
  coverage:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Bun
        uses: oven-sh/setup-bun@v2

      - name: Install dependencies
        run: bun install

      - name: Run tests with coverage
        run: bun test --coverage --coverage-reporter=lcov

      - name: Upload to Codecov
        uses: codecov/codecov-action@v3
        with:
          file: ./coverage/lcov.info
          fail_ci_if_error: true

GitLab CI 示例

yaml
test:coverage:
  stage: test
  script:
    - bun install
    - bun test --coverage --coverage-reporter=lcov
  coverage: '/Lines\s*:\s*(\d+.\d+)%/'
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage/lcov.info

解释覆盖率报告

文本输出解释

-------------|---------|---------|-------------------
File         | % Funcs | % Lines | Uncovered Line #s
-------------|---------|---------|-------------------
All files    |   85.71 |   90.48 |
 src/        |   85.71 |   90.48 |
  utils.ts   |  100.00 |  100.00 |
  api.ts     |   75.00 |   85.71 | 15-18,25
  main.ts    |   80.00 |   88.89 | 42,50-52
-------------|---------|---------|-------------------
  • % Funcs:测试期间调用的函数百分比
  • % Lines:测试期间运行的可执行行百分比
  • Uncovered Line #s:未执行的具体行号

目标覆盖率

  • 80%+ 整体覆盖率:通常被认为是好的
  • 90%+ 关键路径:重要的业务逻辑应该得到充分测试
  • 100% 工具函数:纯函数和工具函数很容易完全测试
  • UI 组件的较低覆盖率:通常可以接受,因为它们可能需要集成测试

最佳实践

关注质量,而不仅仅是数量

ts
// 好:测试实际功能
test("calculateTax 应该处理不同的税率", () => {
  expect(calculateTax(100, 0.08)).toBe(8);
  expect(calculateTax(100, 0.1)).toBe(10);
  expect(calculateTax(0, 0.08)).toBe(0);
});

// 避免:只是为了覆盖而行
test("calculateTax 存在", () => {
  calculateTax(100, 0.08); // 没有断言!
});

测试边界情况

ts
test("用户输入验证", () => {
  // 测试正常情况
  expect(validateEmail("user@example.com")).toBe(true);

  // 测试有意义地提高覆盖率的边界情况
  expect(validateEmail("")).toBe(false);
  expect(validateEmail("invalid")).toBe(false);
  expect(validateEmail(null)).toBe(false);
});

使用覆盖率查找缺失的测试

bash
# 运行覆盖率以识别未经测试的代码
bun test --coverage

# 查看需要关注的具体文件
bun test --coverage src/critical-module.ts

与其他质量指标结合

覆盖率只是一个指标。还要考虑:

  • 代码审查质量
  • 集成测试覆盖率
  • 错误处理测试
  • 性能测试
  • 类型安全

故障排除

某些文件未显示覆盖率

如果文件未出现在覆盖率报告中,它们可能未被测试导入。覆盖率仅跟踪实际加载的文件。

ts
# 确保导入要测试的模块
import { myFunction } from "../src/my-module";

test("我的函数有效", () => {
  expect(myFunction()).toBeDefined();
});

错误的覆盖率报告

如果你看到与预期不符的覆盖率报告:

  1. 检查 source map 是否正常工作
  2. 验证 coveragePathIgnorePatterns 中的文件模式
  3. 确保测试文件实际导入了要测试的代码

大型代码库的性能问题

对于大型项目,覆盖率收集可能会减慢测试速度:

toml
[test]
# 排除你不需要覆盖率的大型目录
coveragePathIgnorePatterns = [
  "node_modules/**",
  "vendor/**",
  "generated/**"
]

考虑仅在 CI 或特定分支上运行覆盖率,而不是在开发期间每次测试运行。

Bun学习网由www.bunjs.com.cn整理维护