> ## Documentation Index
> Fetch the complete documentation index at: https://bun.ll1025.cn/llms.txt
> Use this file to discover all available pages before exploring further.

# 代码覆盖率

> 使用 Bun 内置的代码覆盖率报告来跟踪测试覆盖范围并发现未测试的代码

Bun 的测试运行器内置了代码覆盖率报告。使用它可以了解你的测试覆盖了多少代码库，并发现未测试的代码。

## 启用覆盖率

`bun:test` 可以报告你的测试覆盖了哪些代码行。传递 `--coverage` 可以将覆盖率报告打印到控制台：

```bash terminal icon="terminal" theme={null}
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 title="bunfig.toml" theme={null}
[test]
# 始终启用覆盖率
coverage = true
```

默认情况下，覆盖率报告排除测试文件并使用源码映射。两者都可以在 `bunfig.toml` 中配置。

```toml title="bunfig.toml" icon="settings" theme={null}
[test]
coverageSkipTestFiles = false  # 默认为 true
```

## 覆盖率阈值

在 `bunfig.toml` 中设置覆盖率阈值。如果你的测试套件未达到或超过该阈值，`bun test` 会以非零退出码退出。

### 简单阈值

```toml title="bunfig.toml" icon="settings" theme={null}
[test]
# 要求 90% 的行级和函数级覆盖率
coverageThreshold = 0.9
```

### 详细阈值

```toml title="bunfig.toml" icon="settings" theme={null}
[test]
# 为行和函数设置不同的阈值
coverageThreshold = { lines = 0.9, functions = 0.9, statements = 0.9 }
```

设置任一阈值都会启用 `fail_on_low_coverage`，如果覆盖率低于阈值，则导致测试运行失败。

## 覆盖率报告器

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

要为 CI 或其他工具保存报告，请在命令行传递 `--coverage-reporter=lcov` 或在 `bunfig.toml` 中设置 `coverageReporter`。

```toml title="bunfig.toml" icon="settings" theme={null}
[test]
coverageReporter = ["text", "lcov"]  # 默认为 ["text"]
coverageDir = "path/to/somewhere"    # 默认为 "coverage"
```

### 可用的报告器

| 报告器    | 描述             |
| ------ | -------------- |
| `text` | 将覆盖率文本摘要打印到控制台 |
| `lcov` | 以 lcov 格式保存覆盖率 |

### LCOV 覆盖率报告器

lcov 报告器将 `lcov.info` 文件写入覆盖率目录。

```toml title="bunfig.toml" icon="settings" theme={null}
[test]
coverageReporter = "lcov"
```

```bash terminal icon="terminal" theme={null}
# 或通过 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 title=".github/workflows/test.yml" icon="file-code" theme={null}
name: 带覆盖率的测试
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: 上传覆盖率到 Codecov
        uses: codecov/codecov-action@v3
        with:
          file: ./coverage/lcov.info
```

## 从覆盖率中排除文件

### 跳过测试文件

默认情况下，覆盖率报告排除测试文件。要包含它们：

```toml title="bunfig.toml" icon="settings" theme={null}
[test]
coverageSkipTestFiles = false  # 默认为 true
```

当 `coverageSkipTestFiles` 为 `true`（默认值）时，匹配测试模式的文件（例如 `*.test.ts`、`*.spec.js`）会被排除在覆盖率报告之外。

### 忽略特定路径和模式

`coveragePathIgnorePatterns` 从覆盖率报告中排除特定文件或文件模式：

```toml title="bunfig.toml" icon="settings" theme={null}
[test]
# 单个模式
coveragePathIgnorePatterns = "**/*.spec.ts"

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

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

#### 常见用例

```toml title="bunfig.toml" icon="settings" theme={null}
[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/**"
]
```

## 源码映射

Bun 默认会转译所有文件，生成一个内部源码映射，将原始源代码行映射到 Bun 的内部表示。要禁用此功能，请将 `test.coverageIgnoreSourcemaps` 设置为 `true`；除非在高级用例中，否则很少需要这样做。

```toml title="bunfig.toml" icon="settings" theme={null}
[test]
coverageIgnoreSourcemaps = true  # 默认为 false
```

<Warning>
  使用此选项时，你可能需要在源文件顶部添加 `// @bun` 注释以退出转译过程。
</Warning>

## 覆盖率默认值

默认情况下，覆盖率报告：

* **排除** `node_modules` 目录
* **排除**使用非 JS/TS 加载器加载的文件（例如 `.css`、`.txt`），除非指定了自定义 JS 加载器
* **排除**测试文件本身（可以通过 `coverageSkipTestFiles = false` 包含）
* 可以通过 `coveragePathIgnorePatterns` 排除其他文件

## 高级配置

### 自定义覆盖率目录

```toml title="bunfig.toml" icon="settings" theme={null}
[test]
coverageDir = "coverage-reports"  # 默认为 "coverage"
```

### 多个报告器

```toml title="bunfig.toml" icon="settings" theme={null}
[test]
coverageReporter = ["text", "lcov"]
```

### 带特定测试模式的覆盖率

```bash terminal icon="terminal" theme={null}
# 仅对特定测试文件运行覆盖率
bun test --coverage src/components/*.test.ts

# 运行带名称模式的覆盖率
bun test --coverage --test-name-pattern="API"
```

## CI/CD 集成

### GitHub Actions 示例

```yaml title=".github/workflows/coverage.yml" icon="file-code" theme={null}
name: 覆盖率报告
on: [push, pull_request]

jobs:
  coverage:
    runs-on: ubuntu-latest
    steps:
      - name: 检出代码
        uses: actions/checkout@v4

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

      - name: 安装依赖
        run: bun install

      - name: 运行带覆盖率的测试
        run: bun test --coverage --coverage-reporter=lcov

      - name: 上传到 Codecov
        uses: codecov/codecov-action@v3
        with:
          file: ./coverage/lcov.info
          fail_ci_if_error: true
```

### GitLab CI 示例

```yaml title=".gitlab-ci.yml" theme={null}
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 title="test.ts" icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
// 好：测试实际功能
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 title="test.ts" icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
test("用户输入验证", () => {
  // 测试正常情况
  expect(validateEmail("user@example.com")).toBe(true);

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

### 使用覆盖率发现缺失的测试

```bash terminal icon="terminal" theme={null}
# 运行覆盖率以识别未测试的代码
bun test --coverage

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

### 结合其他质量指标

覆盖率只是一个指标。同时还要考虑：

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

## 故障排除

### 某些文件未显示覆盖率

如果文件未出现在覆盖率报告中，你的测试可能没有导入它们。覆盖率仅跟踪已加载的文件。

```ts title="test.ts" icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
// 确保导入你想要测试的模块
import { myFunction } from "../src/my-module";

test("我的函数正常工作", () => {
  expect(myFunction()).toBeDefined();
});
```

### 覆盖率报告不准确

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

1. 检查源码映射是否正常工作
2. 验证 `coveragePathIgnorePatterns` 中的文件模式
3. 确保测试文件确实在导入要测试的代码

### 大型代码库的性能问题

对于大型项目，收集覆盖率可能会拖慢测试：

```toml title="bunfig.toml" icon="settings" theme={null}
[test]
# 排除你不需要覆盖的大型目录
coveragePathIgnorePatterns = [
  "node_modules/**",
  "vendor/**",
  "generated/**"
]
```

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