Bun测试生命周期 BunTestLifecycle

Bun测试生命周期技能涉及使用Jest兼容的生命周期钩子进行测试设置和清理,包括beforeAll、afterAll、beforeEach、afterEach等,用于管理测试环境、数据库连接、服务器模拟、环境变量设置等,提高测试效率和可靠性。关键词:Bun测试、生命周期钩子、测试自动化、软件测试、测试框架。

测试 0 次安装 0 次浏览 更新于 3/8/2026

name: Bun测试生命周期 description: 用于测试生命周期钩子:beforeAll、afterAll、beforeEach、afterEach、fixtures、preload。 version: 1.0.0

Bun测试生命周期

Bun支持Jest兼容的生命周期钩子用于测试设置和清理。

生命周期钩子

import { test, expect, beforeAll, afterAll, beforeEach, afterEach } from "bun:test";

let db: Database;
let testData: any;

// 在文件中所有测试之前运行一次
beforeAll(async () => {
  db = await Database.connect();
});

// 在文件中所有测试之后运行一次
afterAll(async () => {
  await db.close();
});

// 在每个测试之前运行
beforeEach(() => {
  testData = { id: 1, name: "test" };
});

// 在每个测试之后运行
afterEach(() => {
  testData = null;
});

test("example", () => {
  expect(testData.name).toBe("test");
});

钩子执行顺序

beforeAll
  ├── beforeEach
  │   └── test 1
  │   └── afterEach
  ├── beforeEach
  │   └── test 2
  │   └── afterEach
afterAll

嵌套描述钩子

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

describe("outer", () => {
  beforeAll(() => console.log("1. outer beforeAll"));
  afterAll(() => console.log("6. outer afterAll"));
  beforeEach(() => console.log("2. outer beforeEach"));
  afterEach(() => console.log("5. outer afterEach"));

  describe("inner", () => {
    beforeEach(() => console.log("3. inner beforeEach"));
    afterEach(() => console.log("4. inner afterEach"));

    test("test", () => {
      console.log("test runs here");
    });
  });
});

// 输出:
// 1. outer beforeAll
// 2. outer beforeEach
// 3. inner beforeEach
// test runs here
// 4. inner afterEach
// 5. outer afterEach
// 6. outer afterAll

异步钩子

beforeAll(async () => {
  await setupDatabase();
});

beforeEach(async () => {
  await seedTestData();
});

afterEach(async () => {
  await clearTestData();
});

afterAll(async () => {
  await teardownDatabase();
});

钩子超时

// 为慢速设置设置超时
beforeAll(async () => {
  await slowSetup();
}, 30000); // 30秒

预加载脚本

使用 --preload 进行所有测试文件的全局设置:

bun test --preload ./setup.ts

setup.ts

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

// 全局设置
beforeAll(() => {
  console.log("全局设置在所有测试文件之前运行");
});

// 全局清理
afterAll(() => {
  console.log("全局清理在所有测试文件之后运行");
});

// 设置全局变量
globalThis.testConfig = {
  apiUrl: "http://localhost:3000",
};

在bunfig.toml中配置

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

常见模式

数据库设置

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

let db: Database;

beforeAll(async () => {
  db = await Database.connect(process.env.TEST_DB_URL);
  await db.migrate();
});

afterAll(async () => {
  await db.close();
});

beforeEach(async () => {
  await db.beginTransaction();
});

afterEach(async () => {
  await db.rollback(); // 重置状态
});

服务器设置

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

let server: Server;
let baseUrl: string;

beforeAll(async () => {
  server = Bun.serve({
    port: 0, // 随机可用端口
    fetch: app.fetch,
  });
  baseUrl = `http://localhost:${server.port}`;
});

afterAll(() => {
  server.stop();
});

test("api works", async () => {
  const res = await fetch(`${baseUrl}/api/health`);
  expect(res.ok).toBe(true);
});

模拟设置

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

let fetchSpy: ReturnType<typeof spyOn>;

beforeEach(() => {
  fetchSpy = spyOn(global, "fetch").mockResolvedValue(
    new Response(JSON.stringify({ ok: true }))
  );
});

afterEach(() => {
  fetchSpy.mockRestore();
});

环境变量

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

const originalEnv = process.env;

beforeAll(() => {
  process.env = {
    ...originalEnv,
    NODE_ENV: "test",
    API_KEY: "test-key",
  };
});

afterAll(() => {
  process.env = originalEnv;
});

共享夹具

// fixtures.ts
export async function createTestUser() {
  return { id: 1, name: "Test User" };
}

export async function cleanupTestUser(user: any) {
  // 清理逻辑
}

// 测试文件
import { createTestUser, cleanupTestUser } from "./fixtures";

let user: any;

beforeEach(async () => {
  user = await createTestUser();
});

afterEach(async () => {
  await cleanupTestUser(user);
});

钩子错误

如果钩子抛出错误,该描述块中的所有测试都会失败:

beforeAll(() => {
  throw new Error("设置失败");
});

// 此文件中的所有测试都会失败
test("will fail", () => {
  expect(true).toBe(true);
});

常见错误

错误 原因 修复
beforeAll timeout 慢速异步设置 增加超时时间
Hook not called 错误作用域 检查钩子放置位置
Cleanup not run afterAll被跳过 确保测试中没有抛出错误
State leak 缺少清理 添加适当的afterEach

何时加载参考

加载 references/preload-scripts.md 当:

  • 复杂全局设置
  • 多个预加载文件

加载 references/fixtures.md 当:

  • 可重用测试夹具
  • 工厂模式