Skip to content

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.

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

bash
NODE_ENV=development bun test

TZ (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.

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

bash
TZ=America/New_York bun test

Test-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:

bash
bun test --timeout 10000  # 10 Sekunden

Pro-Test-Timeout

Legen Sie das Timeout pro Test als dritten Parameter der Testfunktion fest:

test.ts
ts
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 Timeout

Unendliches Timeout

Verwenden Sie 0 oder Infinity, um das Timeout zu deaktivieren:

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

test.ts
ts
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 Fehlers

Promise-Ablehnungen

Unbehandelte Promise-Ablehnungen werden ebenfalls abgefangen:

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

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

bash
# Reduziert Speichernutzung für die Test-Runner-VM
bun test --smol

Debugging

bash
# Hängt den Debugger an den Test-Runner-Prozess an
bun test --inspect
bun test --inspect-brk

Modul-Laden

bash
# 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.test

Installationsbezogene Flags

bash
# Beeinflusst Netzwerkanfragen oder Auto-Installs während der Testausführung
bun test --prefer-offline
bun test --frozen-lockfile

Watch 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.

bash
bun test --watch

Der Test-Runner ist intelligent darin, welche Tests erneut ausgeführt werden:

math.test.ts
ts
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:

bash
bun test --hot

Fü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):

test.ts
ts
// 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:

test.ts
ts
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 Fehler
  • 1: Testfehler aufgetreten
  • >1: Anzahl unbehandelter Fehler (auch wenn Tests bestanden)

Signal-Behandlung

Der Test-Runner behandelt gängige Signale ordnungsgemäß:

bash
# 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:

test.ts
ts
// 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

bash
# 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:

test.ts
ts
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

bash
# .env.test erstellen
DATABASE_URL=postgresql://localhost:5432/test_db
API_URL=http://localhost:3001
test.ts
ts
import { 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

bash
# Umgebungsvariablen inline setzen
DATABASE_URL=test bun test

# Oder mit --env-file
bun test --env-file .env.test

In Test-Setup

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

test.ts
ts
// 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:

math.test.ts
ts
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:

component.test.tsx
tsx
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

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

async.test.ts
ts
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

resource.test.ts
ts
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);
});

Bun von www.bunjs.com.cn bearbeitet