Skip to content

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.

HookDescrizione
beforeAllEsegue una volta prima di tutti i test.
beforeEachEsegue prima di ogni test.
afterEachEsegue dopo ogni test.
afterAllEsegue una volta dopo tutti i test.
onTestFinishedEsegue 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.

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

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

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

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

bash
bun test --preload ./setup.ts

Per evitare di digitare --preload ogni volta che esegui i test, puo essere aggiunto al tuo bunfig.toml:

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

Esempi Pratici

Setup del Database

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

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

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

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

test.ts
ts
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");
    });
  });
});
txt
// 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 afterAll

Gestione degli Errori

Se un hook del ciclo di vita lancia un errore, influenzera l'esecuzione dei test:

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

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

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

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

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

Bun a cura di www.bunjs.com.cn