執行環境套件管理器打包器測試執行器程式碼檢查格式化指南參考部落格意見回饋

執行環境行為

瞭解 Bun test 的執行環境整合、環境變數、超時和錯誤處理

bun test 與 Bun 的執行環境深度整合。此整合是 bun test 能夠快速執行的原因之一。

環境變數

NODE_ENV

bun test 會將 $NODE_ENV 設定為 "test",除非它已經在環境或 .env 檔案中設定。大多數測試執行器也會這樣做。

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

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

你可以通過顯式設定 NODE_ENV 來覆蓋預設值:

terminal
NODE_ENV=development bun test

TZ(時區)

除非 TZ 環境變數對其進行覆蓋,否則 bun test 會使用 UTC(Etc/UTC)作為時區。這可以確保日期和時間行為在不同機器上保持一致。

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

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

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

terminal
TZ=America/New_York bun test

測試超時

每個測試的預設超時時間為 5000 毫秒(5 秒)。超出該時間的測試將失敗。

全域性超時

通過 --timeout 選項修改全域性超時:

terminal
bun test --timeout 10000  # 10 秒

每個測試的超時

將每個測試的超時時間作為測試函式的第三個引數:

test.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 秒超時

無限超時

使用 0 或 Infinity 可停用超時:

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

錯誤處理

未捕獲的錯誤

bun test 會跟蹤未處理的 Promise 拒絕以及測試之間發生的錯誤。如果發生任何此類情況,即使沒有測試失敗,bun test 也會以非零退出碼退出。在下面兩個範例中,錯誤都發生在載入檔案時,因此完全不會執行該檔案中的測試。

這有助於捕獲非同步程式碼中的錯誤,否則可能被忽略:

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

test("test 1", () => {
  expect(true).toBe(true);
});

// This error happens outside any test
queueMicrotask(() => {
  throw new Error("Unhandled error");
});

test("test 2", () => {
  expect(true).toBe(true);
});

// bun test reports this as "Unhandled error between tests", does not run
// this file's tests (0 pass, 1 error), and exits with code 1

Promise 拒絕

測試執行器也會捕獲未處理的 Promise 拒絕:

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

test("test 1", () => {
  expect(1).toBe(1);
});

// bun test reports this as "Unhandled error between tests", does not run
// this file's tests, and exits with code 1
Promise.reject(new Error("Unhandled rejection"));

自定義錯誤處理

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

test-setup.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:

記憶體使用

terminal
# 降低測試執行環境 VM 的記憶體使用
bun test --smol

除錯

terminal
# 將偵錯程式附加到測試執行行程
bun test --inspect
bun test --inspect-brk

模組載入

terminal
# 在測試檔案之前執行指令碼(適用於全域性初始化/模擬)
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
# 影響測試執行期間的網路請求或自動安裝
bun test --prefer-offline
bun test --frozen-lockfile

監視和熱過載

監視模式

使用 --watch 標誌時,測試執行器會監視檔案更改並重新執行測試。

terminal
bun test --watch

熱過載

--hot 標誌與之類似,但會更積極地在執行之間保留狀態:

terminal
bun test --hot

對於大多數測試,請使用 --watch:它能在執行之間提供更好的隔離。

全域性變數

以下全域性變數在測試檔案中無需匯入即可使用:

test.ts
// 以下變數均全域性可用
test("全域性 test 函式", () => {
  expect(true).toBe(true);
});

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

  it("全域性 it 函式", () => {
    // it 是 test 的別名
  });
});

// Jest 相容
jest.fn();

// Vitest 相容
vi.fn();

你也可以顯式匯入它們:

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

行程整合

退出碼

bun test 使用標準退出碼:

  • 0: 所有測試通過,沒有未處理的錯誤
  • 1: 發生測試失敗或未處理的錯誤

訊號處理

測試執行器處理常見訊號:

terminal
# 優雅地停止測試執行
kill -SIGTERM <測試行程 PID>

# 立即停止測試執行
kill -SIGKILL <測試行程 PID>

環境檢測

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

test.ts
// GitHub Actions 檢測
if (process.env.GITHUB_ACTIONS) {
  // Bun 自動傳送 GitHub Actions 註釋
}

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

效能考慮

單行程

測試執行器預設在單個行程中執行所有測試。這帶來了:

  • 啟動更快:無需啟動多個行程
  • 共享記憶體:高效利用資源
  • 除錯更簡單:所有測試都在一個行程中執行

但這意味著:

  • 測試共享全域性狀態(使用生命週期鉤子進行清理)
  • 一個測試崩潰可能影響其他測試
  • 不支援真正的單個測試並行

記憶體管理

terminal
# 監控記憶體使用
bun test --smol  # 降低記憶體佔用

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

測試隔離

由於測試執行在同一行程,需確保適當清理:

test.ts
import { afterEach, jest } from "bun:test";

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

  // 如果需要,恢復模擬函式
  jest.restoreAllMocks();
});