5月28日 00:19

如何在 Bun 中进行代码覆盖率统计?

基本用法

Bun 内置了覆盖率收集器,无需额外安装 Istanbul 或 c8 等工具。运行测试时加上 --coverage 参数即可:

bash
bun test --coverage

执行后会在控制台输出覆盖率报告表格:

shell
-------------|---------|---------|------------------- File | % Funcs | % Lines | Uncovered Line #s -------------|---------|---------|------------------- All files | 66.67 | 77.78 | math.ts | 50.00 | 66.67 | 8-12 random.ts | 50.00 | 66.67 | 5-9 -------------|---------|---------|-------------------

报告包含三个核心指标:函数覆盖率(% Funcs)、行覆盖率(% Lines)和未覆盖行号(Uncovered Line #s),让你一眼看到哪些代码路径没有被测试到。

需要注意,Bun 只统计测试执行期间实际被 import/load 的文件。如果一个模块从未被任何测试导入,它不会出现在覆盖率报告中——这是很多开发者踩的坑。对于未被直接导入的工具模块,建议在测试文件中动态 import 确保其被加载。

在 bunfig.toml 中配置覆盖率

Bun 使用 bunfig.toml(注意不是 .bunrc,也不是 package.json)管理项目配置,覆盖率相关的所有选项都可以集中配置:

toml
[test] coverage = true # 默认启用覆盖率 coverageReporter = ["text", "lcov"] # 输出格式:text 控制台、lcov 文件 coverageDir = "./coverage" # 报告输出目录,默认 coverage coverageSkipTestFiles = true # 排除测试文件本身的覆盖率 coveragePathIgnorePatterns = [ # 忽略指定路径 "**/*.spec.ts", "src/generated/**", "*.config.js" ]

其中 coverageSkipTestFiles = true 可以将 *.test.ts 等测试文件从覆盖率统计中排除,避免测试代码本身干扰结果——这在实际项目中经常需要,否则覆盖率数据会被测试辅助代码"稀释"。coveragePathIgnorePatterns 则用于排除生成代码、配置文件等不需要覆盖的路径。

CLI 参数始终优先于 bunfig.toml 配置,临时调整时直接在命令行覆盖即可。

覆盖率阈值与质量门禁

设置覆盖率阈值是保证代码质量的有效手段。Bun 支持在 bunfig.toml 中配置阈值,一旦覆盖率低于设定值,测试将失败退出(非零退出码),适合在 CI 中作为质量门禁。

统一阈值(同时应用于 lines、functions、statements):

toml
[test] coverageThreshold = 0.8

分维度阈值(更精细的控制):

toml
[test] coverageThreshold = { lines = 0.85, functions = 0.80, statements = 0.75 }

设置了 coverageThreshold 后,Bun 会自动启用 fail_on_low_coverage 行为。建议从较低的阈值(如 60%)开始,逐步提高,而不是一上来就要求 90% 以上。过高的阈值会导致团队为达标而写无意义的测试,反而降低代码质量。

有一个已知行为需要注意:coverageThreshold 是按单个文件检查的,即使项目整体覆盖率达标,某个文件不达标也会失败。如果某些文件覆盖率暂时无法达标,可以将其加入 coveragePathIgnorePatterns 排除。

生成 LCOV 报告与 CI 集成

LCOV 是覆盖率报告的通用格式,Codecov、Coveralls 等服务都支持。Bun 可以直接生成 LCOV 报告:

bash
bun test --coverage --coverage-reporter=lcov

生成的 coverage/lcov.info 文件可以上传到覆盖率服务。以下是 GitHub Actions 的完整集成示例:

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

也可以同时输出多种格式,兼顾本地查看和 CI 上传:

bash
bun test --coverage --coverage-reporter=text --coverage-reporter=lcov

这样本地开发时能在终端快速看到摘要,CI 环境中又能自动上传 LCOV 到代码覆盖率平台,在 PR 页面直接展示覆盖率变化趋势。

实战示例:从零搭建覆盖率统计

项目结构:

shell
project/ ├── src/ │ └── math.ts ├── test/ │ └── math.test.ts └── bunfig.toml

步骤一:编写源码 src/math.ts

typescript
export function add(a: number, b: number): number { return a + b; } export function divide(a: number, b: number): number { if (b === 0) throw new Error("Division by zero"); return a / b; }

步骤二:编写测试 test/math.test.ts

typescript
import { test, expect } from "bun:test"; import { add, divide } from "../src/math"; test("add two numbers", () => { expect(add(1, 2)).toBe(3); }); test("divide two numbers", () => { expect(divide(6, 3)).toBe(2); }); test("divide by zero throws", () => { expect(() => divide(1, 0)).toThrow("Division by zero"); });

步骤三:配置 bunfig.toml

toml
[test] coverage = true coverageReporter = ["text", "lcov"] coverageSkipTestFiles = true coverageThreshold = { lines = 0.8, functions = 0.8 }

步骤四:运行并查看结果

bash
bun test --coverage

输出示例:

shell
add two numbers ✓ divide two numbers ✓ divide by zero throws -------------|---------|---------|------------------- File | % Funcs | % Lines | Uncovered Line #s -------------|---------|---------|------------------- All files | 100.00 | 100.00 | math.ts | 100.00 | 100.00 | -------------|---------|---------|-------------------

如果后续新增了 subtract 函数但没有对应测试,覆盖率会下降,低于阈值时测试直接失败,提醒你补充测试。

常见问题

覆盖率报告为空或缺少文件

Bun 只追踪测试期间被加载的文件。确保所有源码模块都被测试文件直接或间接导入。对于工具类文件,可以在测试中添加动态导入:

typescript
test("ensure utils loaded", async () => { await import("../src/utils"); });

覆盖率报告中出现测试文件本身

设置 coverageSkipTestFiles = true 即可排除。默认情况下测试文件会被计入覆盖率,导致统计结果失真。

想只跑部分测试的覆盖率

可以指定测试文件或按名称过滤:

bash
bun test --coverage src/components/*.test.ts bun test --coverage --test-name-pattern="API"
标签:Bun