O executor de testes oferece suporte aos seguintes hooks de lifecycle. Isso é útil para carregar fixtures de teste, mockar dados e configurar o ambiente de teste.
| Hook | Descrição |
|---|---|
beforeAll | Executa uma vez antes de todos os testes. |
beforeEach | Executa antes de cada teste. |
afterEach | Executa após cada teste. |
afterAll | Executa uma vez após todos os testes. |
onTestFinished | Executa após um único teste terminar (após todos afterEach). |
Setup e Teardown por Teste
Execute lógica de setup e teardown por teste com beforeEach e afterEach.
import { beforeEach, afterEach, test } from "bun:test";
beforeEach(() => {
console.log("executando teste.");
});
afterEach(() => {
console.log("teste concluído.");
});
// testes...
test("exemplo de teste", () => {
// Este teste terá beforeEach executado antes dele
// e afterEach executado após ele
});Setup e Teardown por Escopo
Execute lógica de setup e teardown por escopo com beforeAll e afterAll. O escopo é determinado por onde o hook é definido.
Escopo para um Bloco Describe
Para limitar os hooks a um bloco describe específico:
import { describe, beforeAll, afterAll, test } from "bun:test";
describe("grupo de testes", () => {
beforeAll(() => {
// setup para este bloco describe
console.log("Configurando grupo de testes");
});
afterAll(() => {
// teardown para este bloco describe
console.log("Limpando grupo de testes");
});
test("teste 1", () => {
// implementação do teste
});
test("teste 2", () => {
// implementação do teste
});
});Escopo para um Arquivo de Teste
Para limitar os hooks a um arquivo de teste inteiro:
import { describe, beforeAll, afterAll, test } from "bun:test";
beforeAll(() => {
// setup para todo o arquivo
console.log("Configurando arquivo de teste");
});
afterAll(() => {
// teardown para todo o arquivo
console.log("Limpando arquivo de teste");
});
describe("grupo de testes", () => {
test("teste 1", () => {
// implementação do teste
});
});onTestFinished
Use onTestFinished para executar um callback após um único teste ser concluído. É executado após todos os hooks afterEach.
import { test, onTestFinished } from "bun:test";
test("limpar após teste", () => {
onTestFinished(() => {
// executa após todos hooks afterEach
console.log("teste finalizado");
});
});Não suportado em testes concorrentes; use test.serial em vez disso.
Setup e Teardown Global
Para limitar os hooks a uma execução de teste multi-arquivo inteira, defina os hooks em um arquivo separado.
import { beforeAll, afterAll } from "bun:test";
beforeAll(() => {
// setup global
console.log("Setup global de testes");
// Inicializar conexões de banco de dados, iniciar servidores, etc.
});
afterAll(() => {
// teardown global
console.log("Teardown global de testes");
// Fechar conexões de banco de dados, parar servidores, etc.
});Então use --preload para executar o script de setup antes de qualquer arquivo de teste.
bun test --preload ./setup.tsPara evitar digitar --preload toda vez que executar testes, pode ser adicionado ao seu bunfig.toml:
[test]
preload = ["./setup.ts"]Exemplos Práticos
Setup de Banco de Dados
import { beforeAll, afterAll, beforeEach, afterEach } from "bun:test";
import { createConnection, closeConnection, clearDatabase } from "./db";
let connection;
beforeAll(async () => {
// Conectar ao banco de dados de teste
connection = await createConnection({
host: "localhost",
database: "test_db",
});
});
afterAll(async () => {
// Fechar conexão com banco de dados
await closeConnection(connection);
});
beforeEach(async () => {
// Começar com banco de dados limpo para cada teste
await clearDatabase(connection);
});Setup de Servidor API
import { beforeAll, afterAll } from "bun:test";
import { startServer, stopServer } from "./server";
let server;
beforeAll(async () => {
// Iniciar servidor de teste
server = await startServer({
port: 3001,
env: "test",
});
});
afterAll(async () => {
// Parar servidor de teste
await stopServer(server);
});Setup de Mock
import { beforeEach, afterEach } from "bun:test";
import { mock } from "bun:test";
beforeEach(() => {
// Configurar mocks comuns
mock.module("./api-client", () => ({
fetchUser: mock(() => Promise.resolve({ id: 1, name: "Test User" })),
createUser: mock(() => Promise.resolve({ id: 2 })),
}));
});
afterEach(() => {
// Limpar todos mocks após cada teste
mock.restore();
});Hooks de Lifecycle Assíncronos
Todos os hooks de lifecycle oferecem suporte a funções assíncronas:
import { beforeAll, afterAll, test } from "bun:test";
beforeAll(async () => {
// Setup assíncrono
await new Promise(resolve => setTimeout(resolve, 100));
console.log("Setup assíncrono concluído");
});
afterAll(async () => {
// Teardown assíncrono
await new Promise(resolve => setTimeout(resolve, 100));
console.log("Teardown assíncrono concluído");
});
test("teste assíncrono", async () => {
// Teste aguardará beforeAll ser concluído
await expect(Promise.resolve("test")).resolves.toBe("test");
});Hooks Aninhados
Hooks podem ser aninhados e serão executados na ordem apropriada:
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("teste aninhado", () => {
console.log("Teste executando");
});
});
});// Ordem de saída:
// File beforeAll
// Outer beforeAll
// Inner beforeAll
// Outer beforeEach
// Inner beforeEach
// Teste executando
// Inner afterEach
// Outer afterEach
// Inner afterAll
// Outer afterAll
// File afterAllTratamento de Erros
Se um hook de lifecycle lançar um erro, afetará a execução do teste:
import { beforeAll, test } from "bun:test";
beforeAll(() => {
// Se isso lançar, todos testes neste escopo serão ignorados
throw new Error("Setup falhou");
});
test("este teste será ignorado", () => {
// Não será executado porque beforeAll falhou
});Para melhor tratamento de erros:
import { beforeAll, test, expect } from "bun:test";
beforeAll(async () => {
try {
await setupDatabase();
} catch (error) {
console.error("Setup do banco de dados falhou:", error);
throw error; // Re-lançar para falhar a suíte de testes
}
});Melhores Práticas
Mantenha Hooks Simples
// Bom: Setup simples e focado
beforeEach(() => {
clearLocalStorage();
resetMocks();
});
// Evite: Lógica complexa em hooks
beforeEach(async () => {
// Lógica muito complexa torna testes difíceis de depurar
const data = await fetchComplexData();
await processData(data);
await setupMultipleServices(data);
});Use Escopo Apropriado
// Bom: Setup em nível de arquivo para recursos compartilhados
beforeAll(async () => {
await startTestServer();
});
// Bom: Setup em nível de teste para estado específico do teste
beforeEach(() => {
user = createTestUser();
});Limpar Recursos
import { afterAll, afterEach } from "bun:test";
afterEach(() => {
// Limpar após cada teste
document.body.innerHTML = "";
localStorage.clear();
});
afterAll(async () => {
// Limpar recursos caros
await closeDatabase();
await stopServer();
});