Skip to content

bun test 與 Bun 的運行時深度集成。這是使 bun test 快速且易於使用的一部分原因。

環境變量

NODE_ENV

bun test 自動將 $NODE_ENV 設置為 "test",除非它已在環境中或通過 .env 文件設置。這是大多數測試運行器的標准行為,有助於確保一致的測試行為。

ts
import { test, expect } from "bun:test";

test("NODE_ENV 設置為 test", () => {
  expect(process.env.NODE_ENV).toBe("test");
});

你可以通過顯式設置 NODE_ENV 來覆蓋此設置:

bash
NODE_ENV=development bun test

TZ(時區)

默認情況下,所有 bun test 運行都使用 UTC(Etc/UTC)作為時區,除非被 TZ 環境變量覆蓋。這確保了不同開發環境中的日期和時間行為一致。

ts
import { test, expect } from "bun:test";

test("時區默認為 UTC", () => {
  const date = new Date();
  expect(date.getTimezoneOffset()).toBe(0);
});

要使用特定時區進行測試:

bash
TZ=America/New_York bun test

測試超時

如果沒有顯式覆蓋,每個測試的默認超時時間為 5000 毫秒(5 秒)。超過此超時的測試將失敗。

全局超時

使用 --timeout 標志全局更改超時:

bash
bun test --timeout 10000  # 10 秒

每個測試的超時

將超時設置為測試函數的第三個參數:

ts
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 秒超時

無限超時

使用 0Infinity 禁用超時:

ts
test("無超時測試", async () => {
  // 此測試可以無限期運行
  await someVeryLongOperation();
}, 0);

錯誤處理

未處理的錯誤

bun test 跟蹤未處理的 promise 拒絕和測試之間發生的錯誤。如果發生此類錯誤,最終退出碼將為非零(具體為這些錯誤的數量),即使所有測試都通過。

這有助於捕獲異步代碼中否則可能被忽視的錯誤:

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

test("通過的測試", () => {
  expect(1).toBe(1);
});

// 這將導致測試運行失敗
Promise.reject(new Error("未處理的拒絕"));

自定義錯誤處理

你可以在測試設置中設置自定義錯誤處理程序:

ts
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
# 減少測試運行器 VM 的內存使用
bun test --smol

調試

bash
# 將調試器附加到測試運行器進程
bun test --inspect
bun test --inspect-brk

模塊加載

bash
# 在測試文件之前運行腳本(用於全局設置/模擬)
bun test --preload ./setup.ts

# 設置編譯時常量
bun test --define "process.env.API_URL='http://localhost:3000'"

# 配置自定義加載器
bun test --loader .special:special-loader

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

# 為模塊解析設置 package.json 條件
bun test --conditions development

# 為測試加載環境變量
bun test --env-file .env.test

安裝相關的標志

bash
# 影響測試執行期間的任何網絡請求或自動安裝
bun test --prefer-offline
bun test --frozen-lockfile

監視和熱重載

監視模式

使用 --watch 標志運行 bun test 時,測試運行器將監視文件更改並重新運行受影響的測試。

bash
bun test --watch

測試運行器很智能地知道要重新運行哪些測試:

ts
import { add } from "./math.js";
import { test, expect } from "bun:test";

test("加法", () => {
  expect(add(2, 3)).toBe(5);
});

如果你修改 math.js,只有 math.test.ts 將重新運行,而不是所有測試。

熱重載

--hot 標志提供類似的功能,但在嘗試在運行之間保留狀態方面更積極:

bash
bun test --hot

對於大多數測試場景,--watch 是推薦的選項,因為它在測試運行之間提供更好的隔離。

全局變量

以下全局變量在測試文件中自動可用,無需導入(但如果願意,也可以從 bun:test 導入):

ts
// 所有這些都可以在全局范圍內使用
test("全局測試函數", () => {
  expect(true).toBe(true);
});

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

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

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

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

如果你願意,也可以顯式導入它們:

ts
import { test, it, describe, expect, beforeAll, beforeEach, afterAll, afterEach, jest, vi } from "bun:test";

進程集成

退出碼

bun test 使用標准退出碼:

  • 0:所有測試通過,沒有未處理的錯誤
  • 1:測試失敗
  • >1:未處理錯誤的數量(即使測試通過)

信號處理

測試運行器正確處理常見信號:

bash
# 優雅地停止測試執行
kill -SIGTERM <test-process-pid>

# 立即停止測試執行
kill -SIGKILL <test-process-pid>

環境檢測

Bun 自動檢測某些環境並調整行為:

ts
// GitHub Actions 檢測
if (process.env.GITHUB_ACTIONS) {
  // Bun 自動發出 GitHub Actions 注解
}

// CI 檢測
if (process.env.CI) {
  // 某些行為可能會針對 CI 環境進行調整
}

性能考慮

單進程

測試運行器默認在單個進程中運行所有測試。這提供:

  • 更快的啟動 - 無需生成多個進程
  • 共享內存 - 高效的資源使用
  • 簡單的調試 - 所有測試在一個進程中

然而,這意味著:

  • 測試共享全局狀態(使用生命周期鉤子清理)
  • 一個測試崩潰可能影響其他測試
  • 沒有真正的單個測試並行化

內存管理

bash
# 監控內存使用
bun test --smol  # 減少內存佔用

# 對於大型測試套件,考慮拆分文件
bun test src/unit/
bun test src/integration/

測試隔離

由於測試在同一進程中運行,請確保正確清理:

ts
import { afterEach } from "bun:test";

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

  // 如有需要重置模塊
  jest.resetModules();
});

Bun學習網由www.bunjs.com.cn整理維護