Skip to content

Der Test-Runner unterstützt die folgenden Lifecycle-Hooks. Dies ist nützlich zum Laden von Test-Fixtures, Mocken von Daten und Konfigurieren der Testumgebung.

HookBeschreibung
beforeAllWird einmal vor allen Tests ausgeführt.
beforeEachWird vor jedem Test ausgeführt.
afterEachWird nach jedem Test ausgeführt.
afterAllWird einmal nach allen Tests ausgeführt.
onTestFinishedWird ausgeführt, nachdem ein einzelner Test abgeschlossen ist (nach allen afterEach).

Pro-Test-Setup und -Aufräumung

Führen Sie pro-Test-Setup- und -Aufräumlogik mit beforeEach und afterEach aus.

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

beforeEach(() => {
  console.log("Test wird ausgeführt.");
});

afterEach(() => {
  console.log("Mit Test fertig.");
});

// Tests...
test("Beispieltest", () => {
  // Dieser Test lässt beforeEach davor ausführen
  // und afterEach danach
});

Pro-Geltungsbereich-Setup und -Aufräumung

Führen Sie pro-Geltungsbereich-Setup- und -Aufräumlogik mit beforeAll und afterAll aus. Der Geltungsbereich wird dadurch bestimmt, wo der Hook definiert ist.

Auf einen Describe-Block beschränkt

Um die Hooks auf einen bestimmten Describe-Block zu beschränken:

test.ts
ts
import { describe, beforeAll, afterAll, test } from "bun:test";

describe("Testgruppe", () => {
  beforeAll(() => {
    // Setup für diese Describe-Block
    console.log("Testgruppe wird eingerichtet");
  });

  afterAll(() => {
    // Aufräumung für diese Describe-Block
    console.log("Testgruppe wird aufgeräumt");
  });

  test("Test 1", () => {
    // Test-Implementierung
  });

  test("Test 2", () => {
    // Test-Implementierung
  });
});

Auf eine Testdatei beschränkt

Um die Hooks auf eine gesamte Testdatei zu beschränken:

test.ts
ts
import { describe, beforeAll, afterAll, test } from "bun:test";

beforeAll(() => {
  // Setup für gesamte Datei
  console.log("Testdatei wird eingerichtet");
});

afterAll(() => {
  // Aufräumung für gesamte Datei
  console.log("Testdatei wird aufgeräumt");
});

describe("Testgruppe", () => {
  test("Test 1", () => {
    // Test-Implementierung
  });
});

onTestFinished

Verwenden Sie onTestFinished, um einen Callback nach Abschluss eines einzelnen Tests auszuführen. Er wird nach allen afterEach-Hooks ausgeführt.

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

test("Nach Test aufräumen", () => {
  onTestFinished(() => {
    // Wird nach allen afterEach-Hooks ausgeführt
    console.log("Test abgeschlossen");
  });
});

Nicht in gleichzeitigen Tests unterstützt; verwenden Sie stattdessen test.serial.

Globales Setup und Aufräumung

Um die Hooks auf einen gesamten mehrdateiligen Testlauf zu beschränken, definieren Sie die Hooks in einer separaten Datei.

setup.ts
ts
import { beforeAll, afterAll } from "bun:test";

beforeAll(() => {
  // Globales Setup
  console.log("Globales Test-Setup");
  // Datenbankverbindungen initialisieren, Server starten usw.
});

afterAll(() => {
  // Globale Aufräumung
  console.log("Globale Test-Aufräumung");
  // Datenbankverbindungen schließen, Server stoppen usw.
});

Verwenden Sie dann --preload, um das Setup-Skript vor allen Testdateien auszuführen.

bash
bun test --preload ./setup.ts

Um zu vermeiden, dass Sie --preload jedes Mal eingeben müssen, wenn Sie Tests ausführen, kann es zu Ihrer bunfig.toml hinzugefügt werden:

bunfig.toml
toml
[test]
preload = ["./setup.ts"]

Praktische Beispiele

Datenbank-Setup

database-setup.ts
ts
import { beforeAll, afterAll, beforeEach, afterEach } from "bun:test";
import { createConnection, closeConnection, clearDatabase } from "./db";

let connection;

beforeAll(async () => {
  // Mit Test-Datenbank verbinden
  connection = await createConnection({
    host: "localhost",
    database: "test_db",
  });
});

afterAll(async () => {
  // Datenbankverbindung schließen
  await closeConnection(connection);
});

beforeEach(async () => {
  // Mit sauberer Datenbank für jeden Test beginnen
  await clearDatabase(connection);
});

API-Server-Setup

server-setup.ts
ts
import { beforeAll, afterAll } from "bun:test";
import { startServer, stopServer } from "./server";

let server;

beforeAll(async () => {
  // Test-Server starten
  server = await startServer({
    port: 3001,
    env: "test",
  });
});

afterAll(async () => {
  // Test-Server stoppen
  await stopServer(server);
});

Mock-Setup

mock-setup.ts
ts
import { beforeEach, afterEach } from "bun:test";
import { mock } from "bun:test";

beforeEach(() => {
  // Häufige Mocks einrichten
  mock.module("./api-client", () => ({
    fetchUser: mock(() => Promise.resolve({ id: 1, name: "Test Benutzer" })),
    createUser: mock(() => Promise.resolve({ id: 2 })),
  }));
});

afterEach(() => {
  // Alle Mocks nach jedem Test zurücksetzen
  mock.restore();
});

Asynchrone Lifecycle-Hooks

Alle Lifecycle-Hooks unterstützen asynchrone Funktionen:

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

beforeAll(async () => {
  // Asynchrones Setup
  await new Promise(resolve => setTimeout(resolve, 100));
  console.log("Asynchrones Setup abgeschlossen");
});

afterAll(async () => {
  // Asynchrone Aufräumung
  await new Promise(resolve => setTimeout(resolve, 100));
  console.log("Asynchrone Aufräumung abgeschlossen");
});

test("asynchroner Test", async () => {
  // Test wartet auf Abschluss von beforeAll
  await expect(Promise.resolve("test")).resolves.toBe("test");
});

Verschachtelte Hooks

Hooks können verschachtelt werden und werden in der entsprechenden Reihenfolge ausgeführt:

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

beforeAll(() => console.log("Datei beforeAll"));
afterAll(() => console.log("Datei afterAll"));

describe("äußeres Describe", () => {
  beforeAll(() => console.log("Äußeres beforeAll"));
  beforeEach(() => console.log("Äußeres beforeEach"));
  afterEach(() => console.log("Äußeres afterEach"));
  afterAll(() => console.log("Äußeres afterAll"));

  describe("inneres Describe", () => {
    beforeAll(() => console.log("Inneres beforeAll"));
    beforeEach(() => console.log("Inneres beforeEach"));
    afterEach(() => console.log("Inneres afterEach"));
    afterAll(() => console.log("Inneres afterAll"));

    test("verschachtelter Test", () => {
      console.log("Test wird ausgeführt");
    });
  });
});
txt
// Ausgabereihenfolge:
// Datei beforeAll
// Äußeres beforeAll
// Inneres beforeAll
// Äußeres beforeEach
// Inneres beforeEach
// Test wird ausgeführt
// Inneres afterEach
// Äußeres afterEach
// Inneres afterAll
// Äußeres afterAll
// Datei afterAll

Fehlerbehandlung

Wenn ein Lifecycle-Hook einen Fehler wirft, beeinflusst dies die Testausführung:

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

beforeAll(() => {
  // Wenn dies einen Fehler wirft, werden alle Tests in diesem Geltungsbereich übersprungen
  throw new Error("Setup fehlgeschlagen");
});

test("dieser Test wird übersprungen", () => {
  // Dies wird nicht ausgeführt, weil beforeAll fehlgeschlagen ist
});

Für bessere Fehlerbehandlung:

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

beforeAll(async () => {
  try {
    await setupDatabase();
  } catch (error) {
    console.error("Datenbank-Setup fehlgeschlagen:", error);
    throw error; // Erneut werfen, um die Testsuite fehlschlagen zu lassen
  }
});

Best Practices

Hooks einfach halten

test.ts
ts
// Gut: Einfaches, fokussiertes Setup
beforeEach(() => {
  clearLocalStorage();
  resetMocks();
});

// Vermeiden: Komplexe Logik in Hooks
beforeEach(async () => {
  // Zu viel komplexe Logik macht Tests schwer zu debuggen
  const data = await fetchComplexData();
  await processData(data);
  await setupMultipleServices(data);
});

Angemessenen Geltungsbereich verwenden

test.ts
ts
// Gut: Setup auf Dateiebene für gemeinsam genutzte Ressourcen
beforeAll(async () => {
  await startTestServer();
});

// Gut: Setup auf Testebene für testspezifischen Zustand
beforeEach(() => {
  user = createTestUser();
});

Ressourcen aufräumen

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

afterEach(() => {
  // Nach jedem Test aufräumen
  document.body.innerHTML = "";
  localStorage.clear();
});

afterAll(async () => {
  // Teure Ressourcen aufräumen
  await closeDatabase();
  await stopServer();
});

Bun von www.bunjs.com.cn bearbeitet