> ## 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 兼容 Jest 的 API 编写测试，包括异步测试、超时和测试修饰符

使用从内置 `bun:test` 模块导入的类似 Jest 的 API 定义测试。长期来看，Bun 的目标是完全兼容 Jest；目前支持一组有限的 `expect` 匹配器。

## 基本用法

定义测试：

```ts title="math.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 { expect, test } from "bun:test";

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

### 分组测试

使用 `describe` 将测试分组到套件中。

```ts title="math.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 { expect, test, describe } from "bun:test";

describe("算术运算", () => {
  test("2 + 2", () => {
    expect(2 + 2).toBe(4);
  });

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

### 异步测试

测试可以是异步的。

```ts title="math.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 { expect, test } from "bun:test";

test("2 * 2", async () => {
  const result = await Promise.resolve(2 * 2);
  expect(result).toEqual(4);
});
```

或者，使用 `done` 回调来信号测试完成。如果你的测试函数接受 `done` 参数，你必须调用它，否则测试将挂起。

```ts title="math.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 { expect, test } from "bun:test";

test("2 * 2", done => {
  Promise.resolve(2 * 2).then(result => {
    expect(result).toEqual(4);
    done();
  });
});
```

## 超时

可以选择以毫秒为单位指定每个测试的超时时间，将其作为第三个参数传递给 `test`。

```ts title="math.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 { test } from "bun:test";

test("wat", async () => {
  const data = await slowOperation();
  expect(data).toBe(42);
}, 500); // 测试必须在 500ms 内完成
```

在 `bun:test` 中，超时会抛出一个无法捕获的异常，强制测试停止运行并失败。Bun 还会杀死测试中产生的任何子进程，因此它们不会作为僵尸进程残留。

如果未通过此超时选项或 `jest.setTimeout()` 覆盖，每个测试的默认超时为 5000ms（5 秒）。

## 重试和重复

### test.retry

使用 `retry` 选项在失败时自动重试不稳定的测试。如果在指定次数内成功，则测试通过。

```ts title="example.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 { test } from "bun:test";

test(
  "不稳定的网络请求",
  async () => {
    const response = await fetch("https://example.com/api");
    expect(response.ok).toBe(true);
  },
  { retry: 3 }, // 如果测试失败，最多重试 3 次
);
```

### test.repeats

使用 `repeats` 选项多次运行测试，无论通过/失败状态如何；如果任何一次迭代失败，则测试失败。用于检测不稳定的测试或进行压力测试。`repeats: N` 总共运行测试 N+1 次（1 次初始运行 + N 次重复）。

```ts title="example.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 { test } from "bun:test";

test(
  "确保测试稳定",
  () => {
    expect(Math.random()).toBeLessThan(1);
  },
  { repeats: 20 }, // 总共运行 21 次（1 次初始 + 20 次重复）
);
```

<Note>你不能在同一个测试上同时使用 `retry` 和 `repeats`。</Note>

### 🧟 僵尸进程终结者

当测试超时时，Bun 会杀死测试中使用 `Bun.spawn`、`Bun.spawnSync` 或 `node:child_process` 产生的仍在运行的任何进程，并向控制台记录一条消息。这可以防止超时测试后僵尸进程残留。

## 测试修饰符

### test.skip

使用 `test.skip` 跳过个别测试。这些测试不会运行。

```ts title="math.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 { expect, test } from "bun:test";

test.skip("wat", () => {
  // TODO：修复这个
  expect(0.1 + 0.2).toEqual(0.3);
});
```

### test.todo

使用 `test.todo` 将测试标记为待办。这些测试不会运行。

```ts title="math.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 { expect, test } from "bun:test";

test.todo("修复这个", () => {
  myTestFunction();
});
```

要运行待办测试并发现哪些通过了，请使用 `bun test --todo`。

```bash terminal icon="terminal" theme={null}
bun test --todo
```

```
my.test.ts:
✗ 未实现的功能
  ^ 此测试被标记为 todo 但通过了。请移除 `.todo` 或检查测试是否正确。

 0 pass
 1 fail
 1 expect() calls
```

使用此标志时，失败的待办测试不会导致错误，但通过的待办测试会被标记为失败，以便你可以移除待办标记或修复测试。

### test.only

要运行特定的测试或测试套件，请使用 `test.only()` 或 `describe.only()`。

```ts title="example.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 { test, describe } from "bun:test";

test("测试 #1", () => {
  // 不会运行
});

test.only("测试 #2", () => {
  // 会运行
});

describe.only("仅限", () => {
  test("测试 #3", () => {
    // 会运行
  });
});
```

以下命令仅运行测试 #2 和 #3。

```bash terminal icon="terminal" theme={null}
bun test --only
```

### test.if

要有条件地运行测试，请使用 `test.if()`。如果条件为真值，则测试运行。用于应仅在特定架构或操作系统上运行的测试。

```ts title="example.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.if(Math.random() > 0.5)("半数时间运行", () => {
  // ...
});

const macOS = process.platform === "darwin";
test.if(macOS)("在 macOS 上运行", () => {
  // 如果是 macOS 则运行
});
```

### test.skipIf

要基于某个条件跳过测试，请使用 `test.skipIf()` 或 `describe.skipIf()`。

```ts title="example.test.ts" icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
const macOS = process.platform === "darwin";

test.skipIf(macOS)("在非 macOS 上运行", () => {
  // 如果 *不是* macOS 则运行
});
```

### test.todoIf

要将测试标记为 TODO，请使用 `test.todoIf()` 或 `describe.todoIf()`。在 `skipIf` 和 `todoIf` 之间选择能传达意图："此目标无效"与"已计划但尚未实现"。

```ts title="example.test.ts" icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
const macOS = process.platform === "darwin";

// TODO：我们目前只为 Linux 实现了这个。
test.todoIf(macOS)("在 posix 上运行", () => {
  // 如果 *不是* macOS 则运行
});
```

### test.failing

当你已知测试失败但想要跟踪它并在它开始通过时收到通知时，请使用 `test.failing()`。这会反转测试结果：

* 标记了 `.failing()` 的失败测试会通过
* 标记了 `.failing()` 的通过测试会失败，并显示一条消息，表明它现在通过了应该修复

```ts math.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.failing("数学有问题", () => {
  expect(0.1 + 0.2).toBe(0.3); // 由于浮点数精度而失败
});

// 这会失败，并显示一条消息表明测试现在通过了
test.failing("已修复的 bug", () => {
  expect(1 + 1).toBe(2); // 通过了，但我们预期它会失败
});
```

使用它来跟踪你计划稍后修复的已知 bug，或用于测试驱动开发。

## Describe 块的条件测试

条件修饰符 `.if()`、`.skipIf()` 和 `.todoIf()` 也适用于 `describe` 块，影响套件中的所有测试：

```ts title="example.test.ts" icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
const isMacOS = process.platform === "darwin";

// 仅在 macOS 上运行整个套件
describe.if(isMacOS)("macOS 特有功能", () => {
  test("功能 A", () => {
    // 仅在 macOS 上运行
  });

  test("功能 B", () => {
    // 仅在 macOS 上运行
  });
});

// 在 Windows 上跳过整个套件
describe.skipIf(process.platform === "win32")("Unix 功能", () => {
  test("功能 C", () => {
    // 在 Windows 上跳过
  });
});

// 在 Linux 上将整个套件标记为 TODO
describe.todoIf(process.platform === "linux")("即将推出的 Linux 支持", () => {
  test("功能 D", () => {
    // 在 Linux 上标记为 TODO
  });
});
```

## 参数化测试

### `test.each` 和 `describe.each`

要使用多组数据运行相同的测试，请使用 `test.each`。这会创建一个参数化测试，为每个提供的测试用例运行一次。

```ts title="math.test.ts" icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
const cases = [
  [1, 2, 3],
  [3, 4, 7],
];

test.each(cases)("%p + %p 应该是 %p", (a, b, expected) => {
  expect(a + b).toBe(expected);
});
```

`describe.each` 创建一个参数化套件，为每个测试用例运行一次：

```ts title="sum.test.ts" icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
describe.each([
  [1, 2, 3],
  [3, 4, 7],
])("add(%i, %i)", (a, b, expected) => {
  test(`返回 ${expected}`, () => {
    expect(a + b).toBe(expected);
  });

  test(`和大于每个值`, () => {
    expect(a + b).toBeGreaterThan(a);
    expect(a + b).toBeGreaterThan(b);
  });
});
```

### 参数传递方式

参数传递给测试函数的方式取决于测试用例的结构：

* 如果表格行是数组（如 `[1, 2, 3]`），每个元素作为单独的参数传递
* 如果行不是数组（如对象），则作为单个参数传递

```ts title="example.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.each([
  [1, 2, 3],
  [4, 5, 9],
])("add(%i, %i) = %i", (a, b, expected) => {
  expect(a + b).toBe(expected);
});

// 对象项作为单个参数传递
test.each([
  { a: 1, b: 2, expected: 3 },
  { a: 4, b: 5, expected: 9 },
])("add($a, $b) = $expected", data => {
  expect(data.a + data.b).toBe(data.expected);
});
```

### 格式说明符

使用这些说明符来格式化测试标题：

| 说明符  | 描述       |
| ---- | -------- |
| `%p` | 格式化输出    |
| `%s` | 字符串      |
| `%d` | 数字       |
| `%i` | 整数       |
| `%f` | 浮点数      |
| `%j` | JSON     |
| `%o` | 对象       |
| `%#` | 测试用例索引   |
| `%%` | 单个百分号（%） |

#### 示例

```ts title="example.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.each([
  ["hello", 123],
  ["world", 456],
])("字符串: %s, 数字: %i", (str, num) => {
  // "字符串: hello, 数字: 123"
  // "字符串: world, 数字: 456"
});

// %p 用于格式化输出
test.each([
  [{ name: "Alice" }, { a: 1, b: 2 }],
  [{ name: "Bob" }, { x: 5, y: 10 }],
])("用户 %p，数据 %p", (user, data) => {
  // "用户 { name: 'Alice' }，数据 { a: 1, b: 2 }"
  // "用户 { name: 'Bob' }，数据 { x: 5, y: 10 }"
});

// %# 用于索引
test.each(["apple", "banana"])("水果 #%# 是 %s", fruit => {
  // "水果 #0 是 apple"
  // "水果 #1 是 banana"
});
```

## 断言计数

Bun 支持验证测试期间是否调用了特定数量的断言：

### expect.hasAssertions()

使用 `expect.hasAssertions()` 验证测试期间是否至少调用了一个断言：

```ts title="example.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("异步工作调用断言", async () => {
  expect.hasAssertions(); // 如果未调用任何断言，将失败

  const data = await fetchData();
  expect(data).toBeDefined();
});
```

这在异步测试中特别有用，可以确保你的断言被执行。

### expect.assertions(count)

使用 `expect.assertions(count)` 验证测试期间是否调用了特定数量的断言：

```ts title="example.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.assertions(2); // 如果未恰好调用 2 个断言，将失败

  expect(1 + 1).toBe(2);
  expect("hello").toContain("ell");
});
```

这有助于确保所有断言都运行，特别是在具有多个代码路径的复杂异步代码中。

## 类型测试

Bun 包含用于测试 TypeScript 类型的 `expectTypeOf`，与 Vitest 兼容。

### expectTypeOf

<Warning>这些函数在运行时是空操作。需单独运行 TypeScript 来验证类型检查。</Warning>

`expectTypeOf` 函数提供由 TypeScript 的类型检查器检查的类型级断言。要测试你的类型：

1. 使用 `expectTypeOf` 编写类型断言
2. 运行 `bunx tsc --noEmit` 检查你的类型是否正确

```ts title="example.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 { expectTypeOf } from "bun:test";

// 基本类型断言
expectTypeOf<string>().toEqualTypeOf<string>();
expectTypeOf(123).toBeNumber();
expectTypeOf("hello").toBeString();

// 对象类型匹配
expectTypeOf({ a: 1, b: "hello" }).toMatchObjectType<{ a: number }>();

// 函数类型
function greet(name: string): string {
  return `Hello ${name}`;
}

expectTypeOf(greet).toBeFunction();
expectTypeOf(greet).parameters.toEqualTypeOf<[string]>();
expectTypeOf(greet).returns.toEqualTypeOf<string>();

// 数组类型
expectTypeOf([1, 2, 3]).items.toBeNumber();

// Promise 类型
expectTypeOf(Promise.resolve(42)).resolves.toBeNumber();
```

关于 `expectTypeOf` 匹配器的完整文档，请参见[API 参考](https://bun.com/reference/bun/test/expectTypeOf)。

## 匹配器

Bun 实现了以下匹配器。计划实现完全的 Jest 兼容性；参见[跟踪问题](https://github.com/oven-sh/bun/issues/1825)。

### 基本匹配器

| 状态 | 匹配器                |
| -- | ------------------ |
| ✅  | `.not`             |
| ✅  | `.toBe()`          |
| ✅  | `.toEqual()`       |
| ✅  | `.toBeNull()`      |
| ✅  | `.toBeUndefined()` |
| ✅  | `.toBeNaN()`       |
| ✅  | `.toBeDefined()`   |
| ✅  | `.toBeFalsy()`     |
| ✅  | `.toBeTruthy()`    |
| ✅  | `.toStrictEqual()` |

### 字符串和数组匹配器

| 状态 | 匹配器                   |
| -- | --------------------- |
| ✅  | `.toContain()`        |
| ✅  | `.toHaveLength()`     |
| ✅  | `.toMatch()`          |
| ✅  | `.toContainEqual()`   |
| ✅  | `.stringContaining()` |
| ✅  | `.stringMatching()`   |
| ✅  | `.arrayContaining()`  |

### 对象匹配器

| 状态 | 匹配器                     |
| -- | ----------------------- |
| ✅  | `.toHaveProperty()`     |
| ✅  | `.toMatchObject()`      |
| ✅  | `.toContainAllKeys()`   |
| ✅  | `.toContainValue()`     |
| ✅  | `.toContainValues()`    |
| ✅  | `.toContainAllValues()` |
| ✅  | `.toContainAnyValues()` |
| ✅  | `.objectContaining()`   |

### 数字匹配器

| 状态 | 匹配器                         |
| -- | --------------------------- |
| ✅  | `.toBeCloseTo()`            |
| ✅  | `.closeTo()`                |
| ✅  | `.toBeGreaterThan()`        |
| ✅  | `.toBeGreaterThanOrEqual()` |
| ✅  | `.toBeLessThan()`           |
| ✅  | `.toBeLessThanOrEqual()`    |

### 函数和类匹配器

| 状态 | 匹配器                 |
| -- | ------------------- |
| ✅  | `.toThrow()`        |
| ✅  | `.toBeInstanceOf()` |

### Promise 匹配器

| 状态 | 匹配器           |
| -- | ------------- |
| ✅  | `.resolves()` |
| ✅  | `.rejects()`  |

### 模拟函数匹配器

| 状态 | 匹配器                           |
| -- | ----------------------------- |
| ✅  | `.toHaveBeenCalled()`         |
| ✅  | `.toHaveBeenCalledTimes()`    |
| ✅  | `.toHaveBeenCalledWith()`     |
| ✅  | `.toHaveBeenLastCalledWith()` |
| ✅  | `.toHaveBeenNthCalledWith()`  |
| ✅  | `.toHaveReturned()`           |
| ✅  | `.toHaveReturnedTimes()`      |
| ✅  | `.toHaveReturnedWith()`       |
| ✅  | `.toHaveLastReturnedWith()`   |
| ✅  | `.toHaveNthReturnedWith()`    |

### 快照匹配器

| 状态 | 匹配器                                     |
| -- | --------------------------------------- |
| ✅  | `.toMatchSnapshot()`                    |
| ✅  | `.toMatchInlineSnapshot()`              |
| ✅  | `.toThrowErrorMatchingSnapshot()`       |
| ✅  | `.toThrowErrorMatchingInlineSnapshot()` |

### 工具匹配器

| 状态 | 匹配器                |
| -- | ------------------ |
| ✅  | `.extend`          |
| ✅  | `.anything()`      |
| ✅  | `.any()`           |
| ✅  | `.assertions()`    |
| ✅  | `.hasAssertions()` |

### 尚未实现

| 状态 | 匹配器                        |
| -- | -------------------------- |
| ❌  | `.addSnapshotSerializer()` |

## 最佳实践

### 使用描述性测试名称

```ts title="example.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("应计算包含税费的多个商品总价", () => {
  // 测试实现
});

// 避免
test("价格计算", () => {
  // 测试实现
});
```

### 分组相关测试

```ts title="auth.test.ts" icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
describe("用户认证", () => {
  describe("使用有效凭据", () => {
    test("应返回用户数据", () => {
      // 测试实现
    });

    test("应设置认证令牌", () => {
      // 测试实现
    });
  });

  describe("使用无效凭据", () => {
    test("应抛出认证错误", () => {
      // 测试实现
    });
  });
});
```

### 使用合适的匹配器

```ts title="auth.test.ts" icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
// 好：使用特定的匹配器
expect(users).toHaveLength(3);
expect(user.email).toContain("@");
expect(response.status).toBeGreaterThanOrEqual(200);

// 避免：对所有情况都使用 toBe
expect(users.length === 3).toBe(true);
expect(user.email.includes("@")).toBe(true);
expect(response.status >= 200).toBe(true);
```

### 测试错误条件

```ts title="example.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("not-an-email");
  }).toThrow("无效的电子邮件格式");
});

test("应处理异步错误", async () => {
  await expect(async () => {
    await fetchUser("invalid-id");
  }).rejects.toThrow("未找到用户");
});
```

### 使用设置和清理

```ts title="example.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 { beforeEach, afterEach, test } from "bun:test";

let testUser;

beforeEach(() => {
  testUser = createTestUser();
});

afterEach(() => {
  cleanupTestUser(testUser);
});

test("应更新用户资料", () => {
  // 在测试中使用 testUser
});
```
