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.
| Hook | Description |
|---|---|
beforeAll | S'exécute une fois avant tous les tests. |
beforeEach | S'exécute avant chaque test. |
afterEach | S'exécute après chaque test. |
afterAll | S'exécute une fois après tous les tests. |
onTestFinished | S'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.
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 :
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 :
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.
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é.
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.
bun test --preload ./setup.tsPour éviter de taper --preload à chaque fois que vous exécutez des tests, cela peut être ajouté à votre bunfig.toml :
[test]
preload = ["./setup.ts"]Exemples pratiques
Configuration de base de données
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
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
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 :
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é :
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");
});
});
});// 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 afterAllGestion des erreurs
Si un hook de cycle de vie lance une erreur, cela affectera l'exécution des tests :
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 :
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
// 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é
// 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
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();
});