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

# 测试运行器

> Bun 的快速内置 Jest 兼容测试运行器，支持 TypeScript、生命周期钩子、模拟和监视模式

Bun 自带一个快速且与 Jest 兼容的测试运行器。测试在 Bun 运行时中执行，并支持以下功能。

* TypeScript 和 JSX
* 生命周期钩子
* 快照测试
* UI 与 DOM 测试
* 使用 `--watch` 的监视模式
* 使用 `--preload` 的脚本预加载

<Note>
  Bun 旨在兼容 Jest，但并非所有功能均已实现。要跟踪兼容性，请查看[此跟踪问题](https://github.com/oven-sh/bun/issues/1825)。
</Note>

## 运行测试

```bash terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
bun test
```

测试使用 JavaScript 或 TypeScript 编写，并采用类似 Jest 的 API。请参阅[编写测试](/test/writing-tests)。

```ts math.test.ts icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
import { expect, test } from "bun:test";

test("2 + 2", () => {
  expect(2 + 2).toBe(4);
});
```

测试运行器会递归搜索工作目录中符合以下模式的文件：

* `*.test.{js|jsx|ts|tsx|mjs|cjs|mts|cts}`
* `*_test.{js|jsx|ts|tsx|mjs|cjs|mts|cts}`
* `*.spec.{js|jsx|ts|tsx|mjs|cjs|mts|cts}`
* `*_spec.{js|jsx|ts|tsx|mjs|cjs|mts|cts}`

若要筛选要运行的\_测试文件\_，请向 `bun test` 传递其他位置参数。路径与任一筛选条件匹配的测试文件都会运行。筛选条件通常是文件名或目录名；目前尚不支持 glob 模式。

```bash terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
bun test <filter> <filter> ...
```

如果要根据 *测试名称* 过滤，使用 `-t`/`--test-name-pattern` 标志。

```sh terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
# 运行名称中含 "addition" 的所有测试或测试套件
bun test --test-name-pattern addition
```

若要运行特定文件，确保路径以 `./` 或 `/` 开头，以区别于筛选名。

```bash terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
bun test ./test/specific-file.test.ts
```

默认情况下，测试运行器会在单个进程中运行所有测试：它会加载所有 `--preload` 脚本（请参阅[生命周期](/test/lifecycle)），然后在一个共享全局环境中运行每个文件。传入 [`--parallel`](/test/parallel) 可将文件分散到各个 CPU 核心上运行。如果测试失败，测试运行器会以非零退出代码退出。

## CI/CD 集成

`bun test` 支持多种 CI/CD 集成方案。

### GitHub Actions

`bun test` 会自动检测其是否在 GitHub Actions 中运行，并直接向控制台输出 GitHub Actions 注释。

无需额外配置，只需在工作流程中安装 `bun` 并运行 `bun test`。

#### 如何在 GitHub Actions 工作流程中安装 `bun`

要在 GitHub Actions 工作流程中使用 `bun test`，添加如下步骤：

```yaml title=".github/workflows/test.yml" icon="file-code" theme={"theme":{"light":"github-light","dark":"dracula"}}
jobs:
  build:
    name: build-app
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Install bun
        uses: oven-sh/setup-bun@v2
      - name: Install dependencies # （假设你的项目有依赖）
        run: bun install # 如果喜欢，也可以用 npm/yarn/pnpm 代替
      - name: Run tests
        run: bun test
```

### JUnit XML 报告（GitLab 等）

要写入 JUnit XML 报告，请将 `--reporter=junit` 与 `--reporter-outfile` 一起传入。

```sh terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
bun test --reporter=junit --reporter-outfile=./bun.xml
```

`bun test` 仍会像往常一样写入 stdout/stderr，并在运行结束时将 JUnit XML 报告写入指定路径。

JUnit XML 是 CI/CD 管道中报告测试结果的流行格式。

## 超时设置

使用 `--timeout` 标志以毫秒为单位指定\_每个测试\_的超时时间。如果测试超时，则会被标记为失败。默认值为 `5000`。

```bash terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
# 默认值是 5000
bun test --timeout 20
```

## 并发测试执行

要跨 CPU 核运行测试**文件**，请参阅 [`--parallel`](/test/parallel)。以下标志控制文件\_内部\_测试的并发性。

默认情况下，Bun 会在每个测试文件中按顺序运行所有测试。并发执行会并行运行异步测试，从而加快包含相互独立测试的测试套件。

### `--concurrent` 标志

使用 `--concurrent` 标志，实现各测试文件内部的所有测试并发执行：

```sh terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
bun test --concurrent
```

启用此标志后，除非测试标记为 `test.serial`，否则所有测试都会并行运行。

### `--max-concurrency` 标志

用 `--max-concurrency` 标志控制最大并发测试数量：

```sh terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
# 限制最大并发测试为 4 个
bun test --concurrent --max-concurrency 4

# 默认值是 20
bun test --concurrent
```

这有助于防止资源耗尽。默认限制为 20。

### `test.concurrent`

单独标记测试为并发执行，即使未使用 `--concurrent` 也能并行运行：

```ts title="math.test.ts" icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
import { test, expect } from "bun:test";

// 这些测试相互并行运行
test.concurrent("concurrent test 1", async () => {
  await fetch("/api/endpoint1");
  expect(true).toBe(true);
});

test.concurrent("concurrent test 2", async () => {
  await fetch("/api/endpoint2");
  expect(true).toBe(true);
});

// 此测试顺序执行
test("sequential test", () => {
  expect(1 + 1).toBe(2);
});
```

### `test.serial`

即使启用 `--concurrent` 标志，也强制测试顺序执行：

```ts title="math.test.ts" icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
import { test, expect } from "bun:test";

let sharedState = 0;

// 这些测试必须顺序运行
test.serial("first serial test", () => {
  sharedState = 1;
  expect(sharedState).toBe(1);
});

test.serial("second serial test", () => {
  // 依赖前一个测试
  expect(sharedState).toBe(1);
  sharedState = 2;
});

// 如果启用 --concurrent，此测试可并行执行
test("independent test", () => {
  expect(true).toBe(true);
});

// 测试限定符链式调用
test.failing.each([1, 2, 3])("chained qualifiers %d", input => {
  expect(input).toBe(0); // 对每个输入，该测试预期失败
});
```

## 重试失败的测试

使用 `--retry` 标志自动重试失败的测试，最多指定次数。如果测试失败后，在后续尝试中通过，则报告为通过。

```sh terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
bun test --retry 3
```

每个测试可以通过 `{ retry: N }` 设置覆盖全局的 `--retry` 值：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
// 使用全局 --retry 值
test("uses global retry", () => {
  /* ... */
});

// 使用自己的重试次数覆盖 --retry
test("custom retry", { retry: 1 }, () => {
  /* ... */
});
```

你也可以在 `bunfig.toml` 中设置：

```toml title="bunfig.toml" icon="settings" theme={"theme":{"light":"github-light","dark":"dracula"}}
[test]
retry = 3
```

## 重新运行测试

使用 `--rerun-each` 标志多次运行每个测试。这有助于发现不稳定或非确定性的测试失败。

```sh terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
bun test --rerun-each 100
```

## 随机化测试执行顺序

使用 `--randomize` 标志以随机顺序运行测试，有助于发现依赖共享状态或执行顺序的测试。

```sh terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
bun test --randomize
```

使用 `--randomize` 时，用于随机化的种子会显示在测试摘要中：

```sh terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
bun test --randomize
```

```txt theme={"theme":{"light":"github-light","dark":"dracula"}}
# ... 测试输出 ...
 --seed=12345
 2 pass
 8 fail
Ran 10 tests across 2 files. [50.00ms]
```

### 使用 `--seed` 实现可复现的随机顺序

使用 `--seed` 标志指定随机化种子，以便在调试依赖执行顺序的失败测试时复现相同的测试顺序。

```sh terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
# 复现之前的随机运行顺序
bun test --seed 123456
```

`--seed` 标志会隐式启用 `--randomize`，因此无需同时指定这两个标志。相同的种子始终会产生相同的测试执行顺序。

## 失败即停止 `--bail`

使用 `--bail` 标志，在测试失败达到指定次数后中止测试运行。默认情况下，Bun 会运行所有测试并报告所有失败，但在 CI 中，提前停止测试并减少 CPU 使用量可能更为合适。

```sh terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
# 发生 1 次失败即停止
bun test --bail

# 发生 10 次失败即停止
bun test --bail=10
```

## 监视模式

与 `bun run` 类似，`bun test` 接受 `--watch` 标志，以监视更改并重新运行测试。

```bash terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
bun test --watch
```

## 生命周期钩子

Bun 支持以下生命周期钩子：

| 钩子           | 描述          |
| ------------ | ----------- |
| `beforeAll`  | 所有测试开始前执行一次 |
| `beforeEach` | 每个测试开始前执行   |
| `afterEach`  | 每个测试结束后执行   |
| `afterAll`   | 所有测试完成后执行一次 |

在测试文件中定义钩子，或在使用 `--preload` 标志预加载的单独文件中定义钩子。

```sh terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
bun test --preload ./setup.ts
```

请参阅[生命周期](/test/lifecycle)。

## 模拟

使用 `mock` 函数创建模拟函数。

```ts title="math.test.ts" icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
import { test, expect, mock } from "bun:test";
const random = mock(() => Math.random());

test("random", () => {
  const val = random();
  expect(val).toBeGreaterThan(0);
  expect(random).toHaveBeenCalled();
  expect(random).toHaveBeenCalledTimes(1);
});
```

或者使用 `jest.fn()`；其行为完全相同。

```ts title="math.test.ts" icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
import { test, expect, mock } from "bun:test"; // [!code --]
import { test, expect, jest } from "bun:test"; // [!code ++]

const random = mock(() => Math.random()); // [!code --]
const random = jest.fn(() => Math.random()); // [!code ++]
```

请参阅[模拟](/test/mocks)。

## 快照测试

`bun test` 支持快照测试。

```ts title="math.test.ts" icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
// toMatchSnapshot 示例用法
import { test, expect } from "bun:test";

test("snapshot", () => {
  expect({ a: 1 }).toMatchSnapshot();
});
```

要更新快照，请使用 `--update-snapshots` 标志。

```sh terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
bun test --update-snapshots
```

请参阅[快照](/test/snapshots)。

## UI 与 DOM 测试

Bun 兼容流行的 UI 测试库：

* [HappyDOM](https://github.com/capricorn86/happy-dom)
* [DOM Testing Library](https://testing-library.com/docs/dom-testing-library/intro/)
* [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/)

请参阅 [DOM 测试](/test/dom)。

## 大型代码库

对于包含数千个测试文件的测试套件，`bun test` 提供了多个可组合使用的调节项——工作进程、隔离级别、跨机器分片以及基于耗时的调度。每项内容都在[并行与隔离测试运行](/test/parallel)中进行了深入介绍；以下大致按照收益高低说明它们如何配合使用：

**1. 使用每个核心：[`--parallel`](/test/parallel#--parallel)。** 每个核心使用一个工作进程，文件一次分配一个。

**2. 决定所需的隔离程度。** `--parallel` 为每个文件提供一个全新的全局环境，这是安全的默认设置，也是 Jest/Vitest 的行为。如果你的文件之间不会泄漏状态（它们已经能够在共享一个全局环境的普通 `bun test` 下通过），[`--parallel --no-isolate`](/test/parallel#every-file-is-isolated-unless-you-opt-out) 会让每个工作进程只评估一次导入和预加载脚本，而不是每个文件评估一次。对于由许多小文件组成的测试套件，这是最大的单项性能提升——请参阅[对比方式](/test/parallel#how-it-compares)。

**3. 跨机器拆分：[`--shard=i/n`](/test/parallel#splitting-a-suite-across-ci-machines-with---shard)。** 该方式具有确定性且无需协调器；每个 CI 作业运行一个切片，并且每个切片仍会在本地使用 `--parallel`。

**4. 按耗时而非数量进行平衡：[`--timings`](/test/parallel#balancing-with---timings)。** 有了记录的耗时后，分片会被切分，使每个分片的总耗时大致相同（采用最长处理时间优先的方式，同时将路径相邻的文件放在一起，以保持工作进程的模块缓存处于热状态）。每个工作进程会先启动其耗时最长的文件，空闲工作进程则会获取剩余文件中耗时最长的文件——因此运行不会因为某个碰巧最后启动的长耗时文件而被拖慢。

**5. 自动保持耗时数据最新：`--update-timings`。** 每个分片会写入其运行文件的耗时；下一次运行会读取所有这些数据。在 GitHub Actions 中，看起来如下：

```yaml title=".github/workflows/test.yml" icon="github" theme={"theme":{"light":"github-light","dark":"dracula"}}
jobs:
  test:
    strategy:
      matrix:
        shard: [1, 2, 3, 4]
    steps:
      - uses: actions/checkout@v4
      - uses: oven-sh/setup-bun@v2
      - run: bun install
      # last successful run's per-shard timings (nothing on the very first run)
      - uses: actions/cache/restore@v4
        with:
          path: .bun-test-timings
          key: bun-test-timings-${{ github.run_id }}
          restore-keys: bun-test-timings-
      - run: |
          bun test --parallel --shard=${{ matrix.shard }}/4 --update-timings \
            --timings=.bun-test-timings/next/${{ matrix.shard }}.json \
            $(ls .bun-test-timings/*.json 2>/dev/null | sed 's/^/--timings=/')
      - uses: actions/upload-artifact@v4
        with:
          name: timings-${{ matrix.shard }}
          path: .bun-test-timings/next/${{ matrix.shard }}.json
  save-timings:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/download-artifact@v4
        with:
          pattern: timings-*
          path: .bun-test-timings
          merge-multiple: true
      - uses: actions/cache/save@v4
        with:
          path: .bun-test-timings
          key: bun-test-timings-${{ github.run_id }}
```

每个分片都必须读取相同的一组耗时文件，这样各分片的耗时总和才能覆盖整个测试套件。这也是为什么一次运行会读取上一次运行的文件（从缓存中恢复），并将自身的数据写入其他位置，以避免仍在运行的兄弟分片获取这些数据（如上面的 `next/`）。如果第 2 步适用于你，请将 `--no-isolate` 添加到 `bun test` 命令中。

**6. 在文件内部：[`test.concurrent`](#concurrent-test-execution)** 适用于将大部分时间花在等待上的 I/O 密集型测试。

## 性能

Bun 的测试运行器非常快速。

<Frame>
  <img src="https://mintcdn.com/bun-zhcndoc/7hwCkUCcx3ux5DPj/images/buntest.jpeg?fit=max&auto=format&n=7hwCkUCcx3ux5DPj&q=85&s=13944b4ffb6e106ba374b3f78ba1eba6" alt="运行 266 个 React SSR 测试，速度快于 Jest 打印版本号。" width="2112" height="716" data-path="images/buntest.jpeg" />
</Frame>

## AI 代理集成

当你将 Bun 的测试运行器与 AI 编程助手结合使用时，可以启用更安静的输出，在保留失败详情的同时去除其余噪音。

### 环境变量

设置以下任一环境变量即可启用适合 AI 的输出：

* `CLAUDECODE=1` - 适用于 Claude Code
* `REPL_ID=1` - 适用于 Replit
* `AGENT=1` - 通用 AI 代理标志

### 行为

检测到 AI 代理环境时：

* 只详细显示测试失败信息
* 隐藏通过、跳过及待办测试指示符
* 保留统计摘要

```bash terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
# 示例：为 Claude Code 启用安静输出
CLAUDECODE=1 bun test

# 仍显示失败和摘要，隐藏通过测试的详细输出
```

***

# CLI 用法

```bash theme={"theme":{"light":"github-light","dark":"dracula"}}
bun test <patterns>
```

### 执行控制

<ParamField path="--timeout" type="number" default="5000">
  设置每个测试的超时时间，单位为毫秒（默认 5000）
</ParamField>

<ParamField path="--rerun-each" type="number">
  重新运行每个测试文件 <code>NUMBER</code> 次，以帮助发现某些错误
</ParamField>

<ParamField path="--retry" type="number">
  最多重试失败的测试 <code>NUMBER</code> 次。可被每个测试的 <code>{`{ retry: N }`}</code> 覆盖
</ParamField>

<ParamField path="--concurrent" type="boolean">
  将所有测试视为 <code>test.concurrent()</code> 测试
</ParamField>

<ParamField path="--randomize" type="boolean">
  以随机顺序运行测试
</ParamField>

<ParamField path="--seed" type="number">
  设置测试随机化的随机种子
</ParamField>

<ParamField path="--bail" type="number" default="1">
  在出现 <code>NUMBER</code> 次失败后退出测试套件。如果不指定数字，默认为 1。
</ParamField>

<ParamField path="--max-concurrency" type="number" default="20">
  最大同时执行的测试数量（默认 20）
</ParamField>

### 测试过滤

<ParamField path="--todo" type="boolean">
  包含标记为 <code>test.todo()</code> 的测试
</ParamField>

<ParamField path="--test-name-pattern" type="string">
  只运行名称匹配给定正则表达式的测试。别名：<code>-t</code>
</ParamField>

### 报告

<ParamField path="--reporter" type="string">
  测试输出报告格式。可用选项：<code>junit</code>（需要 --reporter-outfile）、<code>dots</code>。默认：控制台输出。
</ParamField>

<ParamField path="--reporter-outfile" type="string">
  报告格式的输出文件路径（与 --reporter 一起使用时必需）
</ParamField>

<ParamField path="--dots" type="boolean">
  启用点状报告。--reporter=dots 的简写
</ParamField>

### 覆盖率

<ParamField path="--coverage" type="boolean">
  生成覆盖率报告
</ParamField>

<ParamField path="--coverage-reporter" type="string" default="text">
  以 <code>text</code> 和/或 <code>lcov</code> 格式报告覆盖率。默认 <code>text</code>
</ParamField>

<ParamField path="--coverage-dir" type="string" default="coverage">
  覆盖率文件的目录。默认 <code>coverage</code>
</ParamField>

### 快照

<ParamField path="--update-snapshots" type="boolean">
  更新快照文件。别名：<code>-u</code>
</ParamField>

## 示例

运行所有测试文件：

```bash terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
bun test
```

运行所有文件名包含 "foo" 或 "bar" 的测试文件：

```bash terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
bun test foo bar
```

运行所有测试文件，仅包含名称中含有 "baz" 的测试：

```bash terminal icon="terminal" theme={"theme":{"light":"github-light","dark":"dracula"}}
bun test --test-name-pattern baz
```
