> ## 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 test` 与 Bun 的运行时深度集成。这种集成是使 `bun test` 快速的部分原因。

## 环境变量

### NODE\_ENV

`bun test` 将 `$NODE_ENV` 设置为 `"test"`，除非它已在环境或 `.env` 文件中设置。大多数测试运行器也是如此。

```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 { test, expect } from "bun:test";

test("NODE_ENV 被设置为 test", () => {
  expect(process.env.NODE_ENV).toBe("test");
});
```

你可以通过显式设置 `NODE_ENV` 来覆盖此行为：

```bash terminal icon="terminal" theme={null}
NODE_ENV=development bun test
```

### TZ（时区）

`bun test` 使用 UTC（`Etc/UTC`）作为时区，除非 `TZ` 环境变量覆盖了它。这可以保持日期和时间行为在不同机器间一致。

```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 { test, expect } from "bun:test";

test("时区默认为 UTC", () => {
  const date = new Date();
  expect(date.getTimezoneOffset()).toBe(0);
});
```

要使用特定时区进行测试：

```bash terminal icon="terminal" theme={null}
TZ=America/New_York bun test
```

## 测试超时

每个测试的默认超时时间为 5000ms（5 秒）。超过此时间的测试将失败。

### 全局超时

使用 `--timeout` 标志全局更改超时时间：

```bash terminal icon="terminal" theme={null}
bun test --timeout 10000  # 10 秒
```

### 每个测试超时

将每个测试的超时时间作为第三个参数传递给测试函数：

```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 { test, expect } from "bun:test";

test("快速测试", () => {
  expect(1 + 1).toBe(2);
}, 1000); // 1 秒超时

test("慢速测试", async () => {
  await new Promise(resolve => setTimeout(resolve, 8000));
}, 10000); // 10 秒超时
```

### 无限超时

使用 `0` 或 `Infinity` 来禁用超时：

```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("无超时的测试", async () => {
  // 此测试可以无限期运行
  await someVeryLongOperation();
}, 0);
```

## 错误处理

### 未处理的错误

`bun test` 会跟踪测试之间发生的未处理的 Promise 拒绝和错误。如果发生任何此类错误，即使所有测试都通过，最终退出码也是非零的。

这有助于捕获异步代码中可能被忽略的错误：

```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 { test } from "bun:test";

test("测试 1", () => {
  // 此测试通过
  expect(true).toBe(true);
});

// 此错误发生在任何测试之外
setTimeout(() => {
  throw new Error("未处理的错误");
}, 0);

test("测试 2", () => {
  // 此测试也通过
  expect(true).toBe(true);
});

// 测试运行仍会以非零退出码失败
// 因为存在未处理的错误
```

### Promise 拒绝

未处理的 Promise 拒绝也会被捕获：

```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 { test } from "bun:test";

test("通过的测试", () => {
  expect(1).toBe(1);
});

// 这将导致测试运行失败
Promise.reject(new Error("未处理的拒绝"));
```

### 自定义错误处理

你可以在测试设置中设置自定义错误处理器：

```ts title="test-setup.ts" icon="https://mintcdn.com/span-inc/82N53aP7NFbaCVSl/icons/typescript.svg?fit=max&auto=format&n=82N53aP7NFbaCVSl&q=85&s=787d39d6a7d96d7f9540dc74344eba23" theme={null}
process.on("uncaughtException", error => {
  console.error("未捕获的异常：", error);
  process.exit(1);
});

process.on("unhandledRejection", (reason, promise) => {
  console.error("未处理的拒绝于：", promise, "原因：", reason);
  process.exit(1);
});
```

## CLI 标志集成

几个 Bun CLI 标志也可以与 `bun test` 一起使用：

### 内存使用

```bash terminal icon="terminal" theme={null}
# 减少测试运行器 VM 的内存使用
bun test --smol
```

### 调试

```bash terminal icon="terminal" theme={null}
# 将调试器附加到测试运行器进程
bun test --inspect
bun test --inspect-brk
```

### 模块加载

```bash terminal icon="terminal" theme={null}
# 在测试文件之前运行脚本（用于全局设置/模拟）
bun test --preload ./setup.ts

# 设置编译时常量
bun test --define "process.env.API_URL='http://localhost:3000'"

# 将文件扩展名映射到内置加载器
bun test --loader .svg:text

# 使用不同的 tsconfig
bun test --tsconfig-override ./test-tsconfig.json

# 设置模块解析的 package.json 条件
bun test --conditions development

# 加载测试的环境变量
bun test --env-file .env.test
```

### 安装相关标志

```bash theme={null}
# 影响测试执行期间的任何网络请求或自动安装
bun test --prefer-offline
bun test --frozen-lockfile
```

## 监视和热重载

### 监视模式

使用 `--watch` 标志，测试运行器会监视文件更改并重新运行测试。

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

### 热重载

`--hot` 标志类似，但更积极地保持运行间的状态：

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

对于大多数测试，使用 `--watch`：它在运行间提供更好的隔离性。

## 全局变量

以下全局变量在测试文件中无需导入即可使用：

```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(true).toBe(true);
});

describe("全局 describe", () => {
  beforeAll(() => {
    // 全局 beforeAll
  });

  it("全局 it 函数", () => {
    // it 是 test 的别名
  });
});

// Jest 兼容性
jest.fn();

// Vitest 兼容性
vi.fn();
```

你也可以显式导入它们：

```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 { test, it, describe, expect, beforeAll, beforeEach, afterAll, afterEach, jest, vi } from "bun:test";
```

## 进程集成

### 退出码

`bun test` 使用标准退出码：

* `0`：所有测试通过，无未处理错误
* `1`：发生测试失败或未处理错误

### 信号处理

测试运行器处理常见信号：

```bash terminal icon="terminal" theme={null}
# 优雅地停止测试执行
kill -SIGTERM <test-process-pid>

# 立即停止测试执行
kill -SIGKILL <test-process-pid>
```

### 环境检测

Bun 会自动检测某些环境并调整行为：

```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}
// GitHub Actions 检测
if (process.env.GITHUB_ACTIONS) {
  // Bun 自动输出 GitHub Actions 注释
}

// CI 检测
if (process.env.CI) {
  // 某些行为可能会根据 CI 环境进行调整
}
```

## 性能考量

### 单进程

默认情况下，测试运行器在单个进程中运行所有测试。这提供了：

* **更快的启动** - 无需产生多个进程
* **共享内存** - 高效的资源使用
* **简单的调试** - 所有测试在同一进程中

但这也意味着：

* 测试共享全局状态（使用生命周期钩子进行清理）
* 一个测试崩溃可能影响其他测试
* 没有真正的单个测试并行化

### 内存管理

```bash terminal icon="terminal" theme={null}
# 监控内存使用
bun test --smol  # 减少内存占用

# 对于大型测试套件，考虑拆分文件
bun test src/unit/
bun test src/integration/
```

### 测试隔离

由于测试在同一个进程中运行，请确保适当的清理：

```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 { afterEach } from "bun:test";

afterEach(() => {
  // 清理全局状态
  global.myGlobalVar = undefined;
  delete process.env.TEST_VAR;

  // 如果需要，恢复模拟函数
  jest.restoreAllMocks();
});
```
