執行環境行為
瞭解 Bun test 的執行環境整合、環境變數、超時和錯誤處理
bun test 與 Bun 的執行環境深度整合。此整合是 bun test 能夠快速執行的原因之一。
環境變數
NODE_ENV
bun test 會將 $NODE_ENV 設定為 "test",除非它已經在環境或 .env 檔案中設定。大多數測試執行器也會這樣做。
import { test, expect } from "bun:test";
test("NODE_ENV 被設定為 test", () => {
expect(process.env.NODE_ENV).toBe("test");
});
你可以通過顯式設定 NODE_ENV 來覆蓋預設值:
NODE_ENV=development bun test
TZ(時區)
除非 TZ 環境變數對其進行覆蓋,否則 bun test 會使用 UTC(Etc/UTC)作為時區。這可以確保日期和時間行為在不同機器上保持一致。
import { test, expect } from "bun:test";
test("預設時區為 UTC", () => {
const date = new Date();
expect(date.getTimezoneOffset()).toBe(0);
});
要使用特定時區進行測試:
TZ=America/New_York bun test
測試超時
每個測試的預設超時時間為 5000 毫秒(5 秒)。超出該時間的測試將失敗。
全域性超時
通過 --timeout 選項修改全域性超時:
bun test --timeout 10000 # 10 秒
每個測試的超時
將每個測試的超時時間作為測試函式的第三個引數:
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("無超時測試", async () => {
// 該測試可以無限執行
await someVeryLongOperation();
}, 0);
錯誤處理
未捕獲的錯誤
bun test 會跟蹤未處理的 Promise 拒絕以及測試之間發生的錯誤。如果發生任何此類情況,即使沒有測試失敗,bun test 也會以非零退出碼退出。在下面兩個範例中,錯誤都發生在載入檔案時,因此完全不會執行該檔案中的測試。
這有助於捕獲非同步程式碼中的錯誤,否則可能被忽略:
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 拒絕:
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"));
自定義錯誤處理
你可以在測試設定中設定自定義錯誤處理器:
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:
記憶體使用
# 降低測試執行環境 VM 的記憶體使用
bun test --smol
除錯
# 將偵錯程式附加到測試執行行程
bun test --inspect
bun test --inspect-brk
模組載入
# 在測試檔案之前執行指令碼(適用於全域性初始化/模擬)
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
相關安裝選項
# 影響測試執行期間的網路請求或自動安裝
bun test --prefer-offline
bun test --frozen-lockfile
監視和熱過載
監視模式
使用 --watch 標誌時,測試執行器會監視檔案更改並重新執行測試。
bun test --watch
熱過載
--hot 標誌與之類似,但會更積極地在執行之間保留狀態:
bun test --hot
對於大多數測試,請使用 --watch:它能在執行之間提供更好的隔離。
全域性變數
以下全域性變數在測試檔案中無需匯入即可使用:
// 以下變數均全域性可用
test("全域性 test 函式", () => {
expect(true).toBe(true);
});
describe("全域性 describe", () => {
beforeAll(() => {
// 全域性 beforeAll
});
it("全域性 it 函式", () => {
// it 是 test 的別名
});
});
// Jest 相容
jest.fn();
// Vitest 相容
vi.fn();
你也可以顯式匯入它們:
import { test, it, describe, expect, beforeAll, beforeEach, afterAll, afterEach, jest, vi } from "bun:test";
行程整合
退出碼
bun test 使用標準退出碼:
0: 所有測試通過,沒有未處理的錯誤1: 發生測試失敗或未處理的錯誤
訊號處理
測試執行器處理常見訊號:
# 優雅地停止測試執行
kill -SIGTERM <測試行程 PID>
# 立即停止測試執行
kill -SIGKILL <測試行程 PID>
環境檢測
Bun 會自動檢測某些環境並調整行為:
// GitHub Actions 檢測
if (process.env.GITHUB_ACTIONS) {
// Bun 自動傳送 GitHub Actions 註釋
}
// CI 檢測
if (process.env.CI) {
// 可能針對 CI 環境調整某些行為
}
效能考慮
單行程
測試執行器預設在單個行程中執行所有測試。這帶來了:
- 啟動更快:無需啟動多個行程
- 共享記憶體:高效利用資源
- 除錯更簡單:所有測試都在一個行程中執行
但這意味著:
- 測試共享全域性狀態(使用生命週期鉤子進行清理)
- 一個測試崩潰可能影響其他測試
- 不支援真正的單個測試並行
記憶體管理
# 監控記憶體使用
bun test --smol # 降低記憶體佔用
# 對於大型測試套件,考慮按檔案拆分
bun test src/unit/
bun test src/integration/
測試隔離
由於測試執行在同一行程,需確保適當清理:
import { afterEach, jest } from "bun:test";
afterEach(() => {
// 清理全域性狀態
global.myGlobalVar = undefined;
delete process.env.TEST_VAR;
// 如果需要,恢復模擬函式
jest.restoreAllMocks();
});