Skip to content

Средство запуска тестов поддерживает следующие хуки жизненного цикла. Это полезно для загрузки тестовых данных, мокирования данных и настройки тестовой среды.

ХукОписание
beforeAllВыполняется один раз перед всеми тестами.
beforeEachВыполняется перед каждым тестом.
afterEachВыполняется после каждого теста.
afterAllВыполняется один раз после всех тестов.
onTestFinishedВыполняется после завершения одного теста (после всех afterEach).

Настройка и очистка для каждого теста

Выполняйте настройку и очистку для каждого теста с помощью beforeEach и afterEach.

ts
import { beforeEach, afterEach, test } from "bun:test";

beforeEach(() => {
  console.log("запуск теста.");
});

afterEach(() => {
  console.log("тест завершён.");
});

// тесты...
test("пример теста", () => {
  // Этот тест будет иметь beforeEach, запущенный перед ним
  // и afterEach, запущенный после него
});

Настройка и очистка для каждой области

Выполняйте настройку и очистку для каждой области с помощью beforeAll и afterAll. Область определяется тем, где определён хук.

Область для блока Describe

Для ограничения области хуков конкретным блоком describe:

ts
import { describe, beforeAll, afterAll, test } from "bun:test";

describe("группа тестов", () => {
  beforeAll(() => {
    // настройка для этой группы describe
    console.log("Настройка группы тестов");
  });

  afterAll(() => {
    // очистка для этой группы describe
    console.log("Очистка группы тестов");
  });

  test("тест 1", () => {
    // реализация теста
  });

  test("тест 2", () => {
    // реализация теста
  });
});

Область для тестового файла

Для ограничения области хуков целым тестовым файлом:

ts
import { describe, beforeAll, afterAll, test } from "bun:test";

beforeAll(() => {
  // настройка для всего файла
  console.log("Настройка тестового файла");
});

afterAll(() => {
  // очистка для всего файла
  console.log("Очистка тестового файла");
});

describe("группа тестов", () => {
  test("тест 1", () => {
    // реализация теста
  });
});

onTestFinished

Используйте onTestFinished для запуска обратного вызова после завершения одного теста. Он выполняется после всех хуков afterEach.

ts
import { test, onTestFinished } from "bun:test";

test("очистка после теста", () => {
  onTestFinished(() => {
    // выполняется после всех хуков afterEach
    console.log("тест завершён");
  });
});

Не поддерживается в параллельных тестах; используйте вместо этого test.serial.

Глобальная настройка и очистка

Для ограничения области хуков целым многофайловым запуском тестов определите хуки в отдельном файле.

ts
import { beforeAll, afterAll } from "bun:test";

beforeAll(() => {
  // глобальная настройка
  console.log("Глобальная настройка тестов");
  // Инициализация подключений к базе данных, запуск серверов и т.д.
});

afterAll(() => {
  // глобальная очистка
  console.log("Глобальная очистка тестов");
  // Закрытие подключений к базе данных, остановка серверов и т.д.
});

Затем используйте --preload для запуска скрипта настройки перед любыми тестовыми файлами.

bash
bun test --preload ./setup.ts

Чтобы не вводить --preload каждый раз при запуске тестов, это можно добавить в ваш bunfig.toml:

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

Практические примеры

Настройка базы данных

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 сервера

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

Настройка моков

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

Асинхронные хуки жизненного цикла

Все хуки жизненного цикла поддерживают асинхронные функции:

ts
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");
});

Вложенные хуки

Хуки могут быть вложенными и будут выполняться в соответствующем порядке:

ts
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");
    });
  });
});
txt
// Порядок вывода:
// File beforeAll
// Outer beforeAll
// Inner beforeAll
// Outer beforeEach
// Inner beforeEach
// Test running
// Inner afterEach
// Outer afterEach
// Inner afterAll
// Outer afterAll
// File afterAll

Обработка ошибок

Если хук жизненного цикла выбрасывает ошибку, это повлияет на выполнение теста:

ts
import { beforeAll, test } from "bun:test";

beforeAll(() => {
  // Если это выбросит ошибку, все тесты в этой области будут пропущены
  throw new Error("Настройка не удалась");
});

test("этот тест будет пропущен", () => {
  // Этот не будет запущен, потому что beforeAll не удался
});

Для лучшей обработки ошибок:

ts
import { beforeAll, test, expect } from "bun:test";

beforeAll(async () => {
  try {
    await setupDatabase();
  } catch (error) {
    console.error("Настройка базы данных не удалась:", error);
    throw error; // Повторно выбросить для неудачи набора тестов
  }
});

Лучшие практики

Держите хуки простыми

ts
// Хорошо: Простая сфокусированная настройка
beforeEach(() => {
  clearLocalStorage();
  resetMocks();
});

// Избегайте: Сложная логика в хуках
beforeEach(async () => {
  // Слишком сложная логика делает тесты трудными для отладки
  const data = await fetchComplexData();
  await processData(data);
  await setupMultipleServices(data);
});

Используйте соответствующую область

ts
// Хорошо: Настройка на уровне файла для общих ресурсов
beforeAll(async () => {
  await startTestServer();
});

// Хорошо: Настройка на уровне теста для специфичного для теста состояния
beforeEach(() => {
  user = createTestUser();
});

Очистка ресурсов

ts
import { afterAll, afterEach } from "bun:test";

afterEach(() => {
  // Очистка после каждого теста
  document.body.innerHTML = "";
  localStorage.clear();
});

afterAll(async () => {
  // Очистка дорогих ресурсов
  await closeDatabase();
  await stopServer();
});

Bun от www.bunjs.com.cn