Il test runner supporta i seguenti hook del ciclo di vita. Questo e utile per caricare fixture di test, mockare dati e configurare l'ambiente di test.
| Hook | Descrizione |
|---|---|
beforeAll | Esegue una volta prima di tutti i test. |
beforeEach | Esegue prima di ogni test. |
afterEach | Esegue dopo ogni test. |
afterAll | Esegue una volta dopo tutti i test. |
onTestFinished | Esegue dopo che un singolo test termina (dopo tutti gli afterEach). |
Setup e Teardown per Test
Esegui la logica di setup e teardown per ogni test con beforeEach e afterEach.
import { beforeEach, afterEach, test } from "bun:test";
beforeEach(() => {
console.log("eseguendo il test.");
});
afterEach(() => {
console.log("finito con il test.");
});
// test...
test("esempio di test", () => {
// Questo test avra beforeEach eseguito prima
// e afterEach eseguito dopo
});Setup e Teardown per Scope
Esegui la logica di setup e teardown per ogni scope con beforeAll e afterAll. Lo scope e determinato da dove e definito l'hook.
Scope di un Blocco Describe
Per applicare lo scope degli hook a un particolare blocco describe:
import { describe, beforeAll, afterAll, test } from "bun:test";
describe("gruppo di test", () => {
beforeAll(() => {
// setup per questo blocco describe
console.log("Impostando il gruppo di test");
});
afterAll(() => {
// teardown per questo blocco describe
console.log("Smontando il gruppo di test");
});
test("test 1", () => {
// implementazione del test
});
test("test 2", () => {
// implementazione del test
});
});Scope di un File di Test
Per applicare lo scope degli hook a un intero file di test:
import { describe, beforeAll, afterAll, test } from "bun:test";
beforeAll(() => {
// setup per l'intero file
console.log("Impostando il file di test");
});
afterAll(() => {
// teardown per l'intero file
console.log("Smontando il file di test");
});
describe("gruppo di test", () => {
test("test 1", () => {
// implementazione del test
});
});onTestFinished
Usa onTestFinished per eseguire un callback dopo che un singolo test termina. Esegue dopo tutti gli hook afterEach.
import { test, onTestFinished } from "bun:test";
test("pulizia dopo il test", () => {
onTestFinished(() => {
// esegue dopo tutti gli hook afterEach
console.log("test terminato");
});
});
Non supportato nei test concorrenti; usa `test.serial` invece.
## Setup e Teardown Globale
Per applicare lo scope degli hook a un'intera esecuzione di test multi-file, definisci gli hook in un file separato.
```ts [setup.ts]
import { beforeAll, afterAll } from "bun:test";
beforeAll(() => {
// setup globale
console.log("Setup globale dei test");
// Inizializza connessioni al database, avvia server, ecc.
});
afterAll(() => {
// teardown globale
console.log("Teardown globale dei test");
// Chiudi connessioni al database, ferma server, ecc.
});Poi usa --preload per eseguire lo script di setup prima di qualsiasi file di test.
bun test --preload ./setup.tsPer evitare di digitare --preload ogni volta che esegui i test, puo essere aggiunto al tuo bunfig.toml:
[test]
preload = ["./setup.ts"]Esempi Pratici
Setup del Database
import { beforeAll, afterAll, beforeEach, afterEach } from "bun:test";
import { createConnection, closeConnection, clearDatabase } from "./db";
let connection;
beforeAll(async () => {
// Connettiti al database di test
connection = await createConnection({
host: "localhost",
database: "test_db",
});
});
afterAll(async () => {
// Chiudi la connessione al database
await closeConnection(connection);
});
beforeEach(async () => {
// Inizia con un database pulito per ogni test
await clearDatabase(connection);
});Setup del Server API
import { beforeAll, afterAll } from "bun:test";
import { startServer, stopServer } from "./server";
let server;
beforeAll(async () => {
// Avvia il server di test
server = await startServer({
port: 3001,
env: "test",
});
});
afterAll(async () => {
// Ferma il server di test
await stopServer(server);
});Setup dei Mock
import { beforeEach, afterEach } from "bun:test";
import { mock } from "bun:test";
beforeEach(() => {
// Imposta i mock comuni
mock.module("./api-client", () => ({
fetchUser: mock(() => Promise.resolve({ id: 1, name: "Test User" })),
createUser: mock(() => Promise.resolve({ id: 2 })),
}));
});
afterEach(() => {
// Cancella tutti i mock dopo ogni test
mock.restore();
});Hook Asincroni
Tutti gli hook del ciclo di vita supportano funzioni asincrone:
import { beforeAll, afterAll, test } from "bun:test";
beforeAll(async () => {
// Setup asincrono
await new Promise(resolve => setTimeout(resolve, 100));
console.log("Setup asincrono completato");
});
afterAll(async () => {
// Teardown asincrono
await new Promise(resolve => setTimeout(resolve, 100));
console.log("Teardown asincrono completato");
});
test("test asincrono", async () => {
// Il test aspettara che beforeAll sia completato
await expect(Promise.resolve("test")).resolves.toBe("test");
});Hook Annidati
Gli hook possono essere annidati e verranno eseguiti nell'ordine appropriato:
import { describe, beforeAll, beforeEach, afterEach, afterAll, test } from "bun:test";
beforeAll(() => console.log("File beforeAll"));
afterAll(() => console.log("File afterAll"));
describe("describe esterno", () => {
beforeAll(() => console.log("BeforeAll esterno"));
beforeEach(() => console.log("BeforeEach esterno"));
afterEach(() => console.log("AfterEach esterno"));
afterAll(() => console.log("AfterAll esterno"));
describe("describe interno", () => {
beforeAll(() => console.log("BeforeAll interno"));
beforeEach(() => console.log("BeforeEach interno"));
afterEach(() => console.log("AfterEach interno"));
afterAll(() => console.log("AfterAll interno"));
test("test annidato", () => {
console.log("Test in esecuzione");
});
});
});// Ordine di output:
// File beforeAll
// BeforeAll esterno
// BeforeAll interno
// BeforeEach esterno
// BeforeEach interno
// Test in esecuzione
// AfterEach interno
// AfterEach esterno
// AfterAll interno
// AfterAll esterno
// File afterAllGestione degli Errori
Se un hook del ciclo di vita lancia un errore, influenzera l'esecuzione dei test:
import { beforeAll, test } from "bun:test";
beforeAll(() => {
// Se questo lancia, tutti i test in questo scope saranno saltati
throw new Error("Setup fallito");
});
test("questo test sara saltato", () => {
// Questo non verra eseguito perche beforeAll e fallito
});Per una migliore gestione degli errori:
import { beforeAll, test, expect } from "bun:test";
beforeAll(async () => {
try {
await setupDatabase();
} catch (error) {
console.error("Setup del database fallito:", error);
throw error; // Rilancia per far fallire la suite di test
}
});Best Practices
Mantieni gli Hook Semplci
// Buono: Setup semplice e focalizzato
beforeEach(() => {
clearLocalStorage();
resetMocks();
});
// Evita: Logica complessa negli hook
beforeEach(async () => {
// Troppa logica complessa rende i test difficili da debuggare
const data = await fetchComplexData();
await processData(data);
await setupMultipleServices(data);
});Usa lo Scope Appropriato
// Buono: Setup a livello di file per risorse condivise
beforeAll(async () => {
await startTestServer();
});
// Buono: Setup a livello di test per stato specifico del test
beforeEach(() => {
user = createTestUser();
});Pulizia delle Risorse
import { afterAll, afterEach } from "bun:test";
afterEach(() => {
// Pulizia dopo ogni test
document.body.innerHTML = "";
localStorage.clear();
});
afterAll(async () => {
// Pulizia delle risorse costose
await closeDatabase();
await stopServer();
});