bun test ist tief in Buns Laufzeit integriert. Dies ist Teil dessen, was bun test schnell und einfach zu verwenden macht.
Umgebungsvariablen
NODE_ENV
bun test setzt automatisch $NODE_ENV auf "test", es sei denn, es ist bereits in der Umgebung oder über .env-Dateien gesetzt. Dies ist Standardverhalten für die meisten Test-Runner und hilft, konsistentes Testverhalten sicherzustellen.
import { test, expect } from "bun:test";
test("NODE_ENV ist auf test gesetzt", () => {
expect(process.env.NODE_ENV).toBe("test");
});Sie können dies überschreiben, indem Sie NODE_ENV explizit setzen:
NODE_ENV=development bun testTZ (Zeitzone)
Standardmäßig verwenden alle bun test-Läufe UTC (Etc/UTC) als Zeitzone, es sei denn, sie wird durch die TZ-Umgebungsvariable überschrieben. Dies stellt konsistentes Datums- und Zeitverhalten über verschiedene Entwicklungsumgebungen hinweg sicher.
import { test, expect } from "bun:test";
test("Zeitzone ist standardmäßig UTC", () => {
const date = new Date();
expect(date.getTimezoneOffset()).toBe(0);
});Um mit einer bestimmten Zeitzone zu testen:
TZ=America/New_York bun testTest-Timeouts
Jeder Test hat standardmäßig ein Timeout von 5000ms (5 Sekunden), wenn nicht explizit überschrieben. Tests, die dieses Timeout überschreiten, schlagen fehl.
Globales Timeout
Ändern Sie das Timeout global mit dem --timeout-Flag:
bun test --timeout 10000 # 10 SekundenPro-Test-Timeout
Legen Sie das Timeout pro Test als dritten Parameter der Testfunktion fest:
import { test, expect } from "bun:test";
test("schneller Test", () => {
expect(1 + 1).toBe(2);
}, 1000); // 1 Sekunde Timeout
test("langsamer Test", async () => {
await new Promise(resolve => setTimeout(resolve, 8000));
}, 10000); // 10 Sekunden TimeoutUnendliches Timeout
Verwenden Sie 0 oder Infinity, um das Timeout zu deaktivieren:
test("Test ohne Timeout", async () => {
// Dieser Test kann unbegrenzt laufen
await someVeryLongOperation();
}, 0);Fehlerbehandlung
Unbehandelte Fehler
bun test verfolgt unbehandelte Promise-Ablehnungen und Fehler, die zwischen Tests auftreten. Wenn solche Fehler auftreten, ist der endgültige Exit-Code ungleich Null (speziell die Anzahl solcher Fehler), selbst wenn alle Tests bestehen.
Dies hilft, Fehler in asynchronem Code zu erkennen, die sonst unbemerkt bleiben könnten:
import { test } from "bun:test";
test("Test 1", () => {
// Dieser Test besteht
expect(true).toBe(true);
});
// Dieser Fehler tritt außerhalb eines Tests auf
setTimeout(() => {
throw new Error("Unbehandelter Fehler");
}, 0);
test("Test 2", () => {
// Dieser Test besteht auch
expect(true).toBe(true);
});
// Der Testlauf schlägt dennoch mit einem Nicht-Null-Exit-Code fehl
// wegen des unbehandelten FehlersPromise-Ablehnungen
Unbehandelte Promise-Ablehnungen werden ebenfalls abgefangen:
import { test } from "bun:test";
test("bestehender Test", () => {
expect(1).toBe(1);
});
// Dies führt dazu, dass der Testlauf fehlschlägt
Promise.reject(new Error("Unbehandelte Ablehnung"));Benutzerdefinierte Fehlerbehandlung
Sie können benutzerdefinierte Fehlerhandler in Ihrem Test-Setup einrichten:
process.on("uncaughtException", error => {
console.error("Unbehandelte Ausnahme:", error);
process.exit(1);
});
process.on("unhandledRejection", (reason, promise) => {
console.error("Unbehandelte Ablehnung bei:", promise, "Grund:", reason);
process.exit(1);
});CLI-Flags-Integration
Mehrere Bun-CLI-Flags können mit bun test verwendet werden, um sein Verhalten zu ändern:
Speichernutzung
# Reduziert Speichernutzung für die Test-Runner-VM
bun test --smolDebugging
# Hängt den Debugger an den Test-Runner-Prozess an
bun test --inspect
bun test --inspect-brkModul-Laden
# Führt Skripte vor Testdateien aus (nützlich für globales Setup/Mocks)
bun test --preload ./setup.ts
# Setzt Compile-Zeit-Konstanten
bun test --define "process.env.API_URL='http://localhost:3000'"
# Konfiguriert benutzerdefinierte Loader
bun test --loader .special:special-loader
# Verwendet eine andere tsconfig
bun test --tsconfig-override ./test-tsconfig.json
# Setzt package.json-Bedingungen für Modulauflösung
bun test --conditions development
# Lädt Umgebungsvariablen für Tests
bun test --env-file .env.testInstallationsbezogene Flags
# Beeinflusst Netzwerkanfragen oder Auto-Installs während der Testausführung
bun test --prefer-offline
bun test --frozen-lockfileWatch und Hot Reloading
Watch-Mode
Bei Verwendung von bun test mit dem --watch-Flag überwacht der Test-Runner Dateiänderungen und führt betroffene Tests erneut aus.
bun test --watchDer Test-Runner ist intelligent darin, welche Tests erneut ausgeführt werden:
import { add } from "./math.js";
import { test, expect } from "bun:test";
test("Addition", () => {
expect(add(2, 3)).toBe(5);
});Wenn Sie math.js ändern, wird nur math.test.ts erneut ausgeführt, nicht alle Tests.
Hot Reloading
Das --hot-Flag bietet ähnliche Funktionalität, ist aber aggressiver beim Versuch, den Zustand zwischen den Läufen zu erhalten:
bun test --hotFür die meisten Testszenarien ist --watch die empfohlene Option, da sie bessere Isolation zwischen Testläufen bietet.
Globale Variablen
Die folgenden Globals sind automatisch in Testdateien verfügbar, ohne zu importieren (obwohl sie bei Bedarf aus bun:test importiert werden können):
// Alle diese sind global verfügbar
test("globale Testfunktion", () => {
expect(true).toBe(true);
});
describe("globales describe", () => {
beforeAll(() => {
// globales beforeAll
});
it("globale it-Funktion", () => {
// it ist ein Alias für test
});
});
// Jest-Kompatibilität
jest.fn();
// Vitest-Kompatibilität
vi.fn();Sie können sie auch explizit importieren, wenn Sie es vorziehen:
import { test, it, describe, expect, beforeAll, beforeEach, afterAll, afterEach, jest, vi } from "bun:test";Prozess-Integration
Exit-Codes
bun test verwendet standardmäßige Exit-Codes:
0: Alle Tests bestanden, keine unbehandelten Fehler1: Testfehler aufgetreten>1: Anzahl unbehandelter Fehler (auch wenn Tests bestanden)
Signal-Behandlung
Der Test-Runner behandelt gängige Signale ordnungsgemäß:
# Beendet Testausführung sanft
kill -SIGTERM <test-process-pid>
# Beendet Testausführung sofort
kill -SIGKILL <test-process-pid>Umgebungserkennung
Bun erkennt automatisch bestimmte Umgebungen und passt das Verhalten an:
// GitHub Actions-Erkennung
if (process.env.GITHUB_ACTIONS) {
// Bun gibt automatisch GitHub Actions-Annotationen aus
}
// CI-Erkennung
if (process.env.CI) {
// Bestimmte Verhaltensweisen können für CI-Umgebungen angepasst werden
}Performance-Überlegungen
Einzelner Prozess
Der Test-Runner führt standardmäßig alle Tests in einem einzigen Prozess aus. Dies bietet:
- Schnellerer Start - Keine Notwendigkeit, mehrere Prozesse zu starten
- Gemeinsamer Speicher - Effiziente Ressourcennutzung
- Einfaches Debugging - Alle Tests in einem Prozess
Dies bedeutet jedoch:
- Tests teilen sich globalen Zustand (verwenden Sie Lifecycle-Hooks zum Aufräumen)
- Ein Test-Absturz kann andere beeinflussen
- Keine echte Parallelisierung einzelner Tests
Speicherverwaltung
# Speichernutzung überwachen
bun test --smol # Reduziert Speicherbedarf
# Für große Testsuiten erwägen, Dateien aufzuteilen
bun test src/unit/
bun test src/integration/Test-Isolation
Da Tests im selben Prozess ausgeführt werden, stellen Sie eine ordnungsgemäße Bereinigung sicher:
import { afterEach } from "bun:test";
afterEach(() => {
// Globalen Zustand bereinigen
global.myGlobalVar = undefined;
delete process.env.TEST_VAR;
// Module bei Bedarf zurücksetzen
jest.resetModules();
});Umgebungsvariablen für Tests
Sie können Umgebungsvariablen für Tests auf verschiedene Arten setzen:
.env-Dateien
# .env.test erstellen
DATABASE_URL=postgresql://localhost:5432/test_db
API_URL=http://localhost:3001import { test, expect } from "bun:test";
test("Umgebungsvariablen laden", () => {
expect(process.env.DATABASE_URL).toContain("test_db");
expect(process.env.API_URL).toBe("http://localhost:3001");
});CLI-Flags
# Umgebungsvariablen inline setzen
DATABASE_URL=test bun test
# Oder mit --env-file
bun test --env-file .env.testIn Test-Setup
process.env.NODE_ENV = "test";
process.env.LOG_LEVEL = "error";
process.env.SUPPRESS_WARNINGS = "true";Module Resolution in Tests
Bun verwendet dieselbe Modulauflösung für Tests wie für normalen Code:
// Relative Importe
import { myFunction } from "./my-module";
// Paket-Importe
import express from "express";
// Absolute Importe (mit tsconfig paths)
import { utils } from "@/utils";TypeScript-Unterstützung
Bun transpiliert TypeScript automatisch während des Testens:
import { test, expect } from "bun:test";
function add(a: number, b: number): number {
return a + b;
}
test("Addition", () => {
expect(add(2, 3)).toBe(5);
});JSX-Unterstützung
JSX wird in Tests ohne zusätzliche Konfiguration unterstützt:
import { test, expect } from "bun:test";
function Button({ children }: { children: React.ReactNode }) {
return <button>{children}</button>;
}
test("Button rendert", () => {
const button = <Button>Klick mich</Button>;
expect(button).toBeDefined();
});Best Practices
Test-Umgebung isolieren
import { beforeEach, afterEach } from "bun:test";
beforeEach(() => {
// Sauberen Zustand für jeden Test sicherstellen
jest.clearAllMocks();
process.env = { ...process.env, NODE_ENV: "test" };
});
afterEach(() => {
// Nach jedem Test bereinigen
jest.restoreAllMocks();
});Asynchrone Tests richtig handhaben
import { test, expect } from "bun:test";
test("asynchrone Operation", async () => {
const result = await asyncFunction();
expect(result).toBe("expected");
});
test("Promise-basierte Assertion", async () => {
await expect(asyncFunction()).resolves.toBe("expected");
await expect(failingFunction()).rejects.toThrow("error");
});Ressourcen verwalten
import { test, expect, beforeEach, afterEach } from "bun:test";
let server;
beforeEach(async () => {
server = await startTestServer();
});
afterEach(async () => {
await server.stop();
});
test("Server antwortet", async () => {
const response = await fetch(server.url);
expect(response.status).toBe(200);
});