Средство запуска тестов поддерживает следующие хуки жизненного цикла. Это полезно для загрузки тестовых данных, мокирования данных и настройки тестовой среды.
| Хук | Описание |
|---|---|
beforeAll | Выполняется один раз перед всеми тестами. |
beforeEach | Выполняется перед каждым тестом. |
afterEach | Выполняется после каждого теста. |
afterAll | Выполняется один раз после всех тестов. |
onTestFinished | Выполняется после завершения одного теста (после всех afterEach). |
Настройка и очистка для каждого теста
Выполняйте настройку и очистку для каждого теста с помощью beforeEach и afterEach.
import { beforeEach, afterEach, test } from "bun:test";
beforeEach(() => {
console.log("запуск теста.");
});
afterEach(() => {
console.log("тест завершён.");
});
// тесты...
test("пример теста", () => {
// Этот тест будет иметь beforeEach, запущенный перед ним
// и afterEach, запущенный после него
});Настройка и очистка для каждой области
Выполняйте настройку и очистку для каждой области с помощью beforeAll и afterAll. Область определяется тем, где определён хук.
Область для блока Describe
Для ограничения области хуков конкретным блоком describe:
import { describe, beforeAll, afterAll, test } from "bun:test";
describe("группа тестов", () => {
beforeAll(() => {
// настройка для этой группы describe
console.log("Настройка группы тестов");
});
afterAll(() => {
// очистка для этой группы describe
console.log("Очистка группы тестов");
});
test("тест 1", () => {
// реализация теста
});
test("тест 2", () => {
// реализация теста
});
});Область для тестового файла
Для ограничения области хуков целым тестовым файлом:
import { describe, beforeAll, afterAll, test } from "bun:test";
beforeAll(() => {
// настройка для всего файла
console.log("Настройка тестового файла");
});
afterAll(() => {
// очистка для всего файла
console.log("Очистка тестового файла");
});
describe("группа тестов", () => {
test("тест 1", () => {
// реализация теста
});
});onTestFinished
Используйте onTestFinished для запуска обратного вызова после завершения одного теста. Он выполняется после всех хуков afterEach.
import { test, onTestFinished } from "bun:test";
test("очистка после теста", () => {
onTestFinished(() => {
// выполняется после всех хуков afterEach
console.log("тест завершён");
});
});Не поддерживается в параллельных тестах; используйте вместо этого test.serial.
Глобальная настройка и очистка
Для ограничения области хуков целым многофайловым запуском тестов определите хуки в отдельном файле.
import { beforeAll, afterAll } from "bun:test";
beforeAll(() => {
// глобальная настройка
console.log("Глобальная настройка тестов");
// Инициализация подключений к базе данных, запуск серверов и т.д.
});
afterAll(() => {
// глобальная очистка
console.log("Глобальная очистка тестов");
// Закрытие подключений к базе данных, остановка серверов и т.д.
});Затем используйте --preload для запуска скрипта настройки перед любыми тестовыми файлами.
bun test --preload ./setup.tsЧтобы не вводить --preload каждый раз при запуске тестов, это можно добавить в ваш bunfig.toml:
[test]
preload = ["./setup.ts"]Практические примеры
Настройка базы данных
import { beforeAll, afterAll, beforeEach, afterEach } from "bun:test";
import { createConnection, closeConnection, clearDatabase } from "./db";
let connection;
beforeAll(async () => {
// Подключение к тестовой базе данных
connection = await createConnection({
host: "localhost",
database: "test_db",
});
});
afterAll(async () => {
// Закрытие подключения к базе данных
await closeConnection(connection);
});
beforeEach(async () => {
// Начать с чистой базой данных для каждого теста
await clearDatabase(connection);
});Настройка API сервера
import { beforeAll, afterAll } from "bun:test";
import { startServer, stopServer } from "./server";
let server;
beforeAll(async () => {
// Запуск тестового сервера
server = await startServer({
port: 3001,
env: "test",
});
});
afterAll(async () => {
// Остановка тестового сервера
await stopServer(server);
});Настройка моков
import { beforeEach, afterEach } from "bun:test";
import { mock } from "bun:test";
beforeEach(() => {
// Настройка общих моков
mock.module("./api-client", () => ({
fetchUser: mock(() => Promise.resolve({ id: 1, name: "Test User" })),
createUser: mock(() => Promise.resolve({ id: 2 })),
}));
});
afterEach(() => {
// Очистка всех моков после каждого теста
mock.restore();
});Асинхронные хуки жизненного цикла
Все хуки жизненного цикла поддерживают асинхронные функции:
import { beforeAll, afterAll, test } from "bun:test";
beforeAll(async () => {
// Асинхронная настройка
await new Promise(resolve => setTimeout(resolve, 100));
console.log("Асинхронная настройка завершена");
});
afterAll(async () => {
// Асинхронная очистка
await new Promise(resolve => setTimeout(resolve, 100));
console.log("Асинхронная очистка завершена");
});
test("асинхронный тест", async () => {
// Тест будет ждать завершения beforeAll
await expect(Promise.resolve("test")).resolves.toBe("test");
});Вложенные хуки
Хуки могут быть вложенными и будут выполняться в соответствующем порядке:
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("nested test", () => {
console.log("Test running");
});
});
});// Порядок вывода:
// File beforeAll
// Outer beforeAll
// Inner beforeAll
// Outer beforeEach
// Inner beforeEach
// Test running
// Inner afterEach
// Outer afterEach
// Inner afterAll
// Outer afterAll
// File afterAllОбработка ошибок
Если хук жизненного цикла выбрасывает ошибку, это повлияет на выполнение теста:
import { beforeAll, test } from "bun:test";
beforeAll(() => {
// Если это выбросит ошибку, все тесты в этой области будут пропущены
throw new Error("Настройка не удалась");
});
test("этот тест будет пропущен", () => {
// Этот не будет запущен, потому что beforeAll не удался
});Для лучшей обработки ошибок:
import { beforeAll, test, expect } from "bun:test";
beforeAll(async () => {
try {
await setupDatabase();
} catch (error) {
console.error("Настройка базы данных не удалась:", error);
throw error; // Повторно выбросить для неудачи набора тестов
}
});Лучшие практики
Держите хуки простыми
// Хорошо: Простая сфокусированная настройка
beforeEach(() => {
clearLocalStorage();
resetMocks();
});
// Избегайте: Сложная логика в хуках
beforeEach(async () => {
// Слишком сложная логика делает тесты трудными для отладки
const data = await fetchComplexData();
await processData(data);
await setupMultipleServices(data);
});Используйте соответствующую область
// Хорошо: Настройка на уровне файла для общих ресурсов
beforeAll(async () => {
await startTestServer();
});
// Хорошо: Настройка на уровне теста для специфичного для теста состояния
beforeEach(() => {
user = createTestUser();
});Очистка ресурсов
import { afterAll, afterEach } from "bun:test";
afterEach(() => {
// Очистка после каждого теста
document.body.innerHTML = "";
localStorage.clear();
});
afterAll(async () => {
// Очистка дорогих ресурсов
await closeDatabase();
await stopServer();
});