Skip to content

Le runner de tests prend en charge les hooks de cycle de vie suivants. Ceci est utile pour charger des fixtures de test, mocker des données et configurer l'environnement de test.

HookDescription
beforeAllS'exécute une fois avant tous les tests.
beforeEachS'exécute avant chaque test.
afterEachS'exécute après chaque test.
afterAllS'exécute une fois après tous les tests.
onTestFinishedS'exécute après la fin d'un seul test (après tous les afterEach).

Configuration et nettoyage par test

Effectuez une configuration et un nettoyage par test avec beforeEach et afterEach.

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

beforeEach(() => {
  console.log("exécution du test.");
});

afterEach(() => {
  console.log("test terminé.");
});

// tests...
test("exemple de test", () => {
  // Ce test exécutera beforeEach avant lui
  // et afterEach après lui
});

Configuration et nettoyage par scope

Effectuez une configuration et un nettoyage par scope avec beforeAll et afterAll. Le scope est déterminé par l'endroit où le hook est défini.

Scope à un bloc Describe

Pour limiter les hooks à un bloc describe particulier :

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

describe("groupe de tests", () => {
  beforeAll(() => {
    // configuration pour ce bloc describe
    console.log("Configuration du groupe de tests");
  });

  afterAll(() => {
    // nettoyage pour ce bloc describe
    console.log("Nettoyage du groupe de tests");
  });

  test("test 1", () => {
    // implémentation du test
  });

  test("test 2", () => {
    // implémentation du test
  });
});

Scope à un fichier de test

Pour limiter les hooks à un fichier de test entier :

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

beforeAll(() => {
  // configuration pour le fichier entier
  console.log("Configuration du fichier de test");
});

afterAll(() => {
  // nettoyage pour le fichier entier
  console.log("Nettoyage du fichier de test");
});

describe("groupe de tests", () => {
  test("test 1", () => {
    // implémentation du test
  });
});

onTestFinished

Utilisez onTestFinished pour exécuter un callback après la fin d'un seul test. Il s'exécute après tous les hooks afterEach.

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

test("nettoyage après le test", () => {
  onTestFinished(() => {
    // s'exécute après tous les hooks afterEach
    console.log("test terminé");
  });
});

Non pris en charge dans les tests concurrents ; utilisez test.serial à la place.

Configuration et nettoyage globaux

Pour limiter les hooks à une exécution de tests multi-fichiers entière, définissez les hooks dans un fichier séparé.

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

beforeAll(() => {
  // configuration globale
  console.log("Configuration globale des tests");
  // Initialiser les connexions base de données, démarrer les serveurs, etc.
});

afterAll(() => {
  // nettoyage global
  console.log("Nettoyage global des tests");
  // Fermer les connexions base de données, arrêter les serveurs, etc.
});

Puis utilisez --preload pour exécuter le script de configuration avant tous les fichiers de test.

bash
bun test --preload ./setup.ts

Pour éviter de taper --preload à chaque fois que vous exécutez des tests, cela peut être ajouté à votre bunfig.toml :

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

Exemples pratiques

Configuration de base de données

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

let connection;

beforeAll(async () => {
  // Se connecter à la base de données de test
  connection = await createConnection({
    host: "localhost",
    database: "test_db",
  });
});

afterAll(async () => {
  // Fermer la connexion à la base de données
  await closeConnection(connection);
});

beforeEach(async () => {
  // Commencer avec une base de données propre pour chaque test
  await clearDatabase(connection);
});

Configuration de serveur API

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

let server;

beforeAll(async () => {
  // Démarrer le serveur de test
  server = await startServer({
    port: 3001,
    env: "test",
  });
});

afterAll(async () => {
  // Arrêter le serveur de test
  await stopServer(server);
});

Configuration de mock

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

beforeEach(() => {
  // Configurer des mocks communs
  mock.module("./api-client", () => ({
    fetchUser: mock(() => Promise.resolve({ id: 1, name: "Test User" })),
    createUser: mock(() => Promise.resolve({ id: 2 })),
  }));
});

afterEach(() => {
  // Effacer tous les mocks après chaque test
  mock.restore();
});

Hooks de cycle de vie async

Tous les hooks de cycle de vie prennent en charge les fonctions async :

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

beforeAll(async () => {
  // Configuration async
  await new Promise(resolve => setTimeout(resolve, 100));
  console.log("Configuration async terminée");
});

afterAll(async () => {
  // Nettoyage async
  await new Promise(resolve => setTimeout(resolve, 100));
  console.log("Nettoyage async terminé");
});

test("test async", async () => {
  // Le test attendra que beforeAll soit terminé
  await expect(Promise.resolve("test")).resolves.toBe("test");
});

Hooks imbriqués

Les hooks peuvent être imbriqués et s'exécuteront dans l'ordre approprié :

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

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

describe("outer describe", () => {
  beforeAll(() => console.log("Outer beforeAll"));
  beforeEach(() => console.log("Outer beforeEach"));
  afterEach(() => console.log("Outer afterEach"));
  afterAll(() => console.log("Outer afterAll"));

  describe("inner describe", () => {
    beforeAll(() => console.log("Inner beforeAll"));
    beforeEach(() => console.log("Inner beforeEach"));
    afterEach(() => console.log("Inner afterEach"));
    afterAll(() => console.log("Inner afterAll"));

    test("test imbriqué", () => {
      console.log("Test en cours");
    });
  });
});
txt
// Ordre de sortie :
// File beforeAll
// Outer beforeAll
// Inner beforeAll
// Outer beforeEach
// Inner beforeEach
// Test en cours
// Inner afterEach
// Outer afterEach
// Inner afterAll
// Outer afterAll
// File afterAll

Gestion des erreurs

Si un hook de cycle de vie lance une erreur, cela affectera l'exécution des tests :

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

beforeAll(() => {
  // Si cela lance, tous les tests dans ce scope seront ignorés
  throw new Error("La configuration a échoué");
});

test("ce test sera ignoré", () => {
  // Cela ne s'exécutera pas car beforeAll a échoué
});

Pour une meilleure gestion des erreurs :

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

beforeAll(async () => {
  try {
    await setupDatabase();
  } catch (error) {
    console.error("La configuration de la base de données a échoué :", error);
    throw error; // Re-lancer pour échouer la suite de tests
  }
});

Bonnes pratiques

Garder les hooks simples

ts
// Bien : Configuration simple et ciblée
beforeEach(() => {
  clearLocalStorage();
  resetMocks();
});

// Éviter : Logique complexe dans les hooks
beforeEach(async () => {
  // Trop de logique complexe rend les tests difficiles à déboguer
  const data = await fetchComplexData();
  await processData(data);
  await setupMultipleServices(data);
});

Utiliser le scope approprié

ts
// Bien : Configuration au niveau du fichier pour les ressources partagées
beforeAll(async () => {
  await startTestServer();
});

// Bien : Configuration au niveau du test pour l'état spécifique au test
beforeEach(() => {
  user = createTestUser();
});

Nettoyer les ressources

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

afterEach(() => {
  // Nettoyer après chaque test
  document.body.innerHTML = "";
  localStorage.clear();
});

afterAll(async () => {
  // Nettoyer les ressources coûteuses
  await closeDatabase();
  await stopServer();
});

Bun édité par www.bunjs.com.cn