首页 / 编程实战 / Bun 2.0 实战:原生 TypeScript 测试框架与快照测试最佳实践 2 次阅读
Bun 2.0 实战:原生 TypeScript 测试框架与快照测试最佳实践
编程实战

Bun 2.0 实战:原生 TypeScript 测试框架与快照测试最佳实践

从零配置到 CI 集成,掌握 Bun 原生测试运行器的完整工作流

2026 年 3 月 2 日 · 约 12 分钟阅读

为什么需要 Bun 测试框架?

在 2026 年的现代 JavaScript/TypeScript 开发中,测试工具链的选择直接影响开发效率。传统的 Jest + ts-node + babel 组合需要多层配置,启动速度慢,内存占用高。而 Bun 2.0 内置的测试运行器提供了零配置、原生 TypeScript 支持、毫秒级启动的全新体验。

本教程将带你从零开始,掌握 Bun 2.0 测试框架的核心功能,包括:

  • 环境搭建与类型配置
  • 基础测试语法与断言
  • 快照测试完整工作流
  • Mock 与生命周期钩子
  • 并发测试与性能优化
  • CI/CD 集成实战
Bun 测试框架与传统工具对比图

准备工作

📦
Bun 2.0+
高性能 JavaScript 运行时
TypeScript 5.7+
类型安全支持
🔧
bun-types
Bun 类型定义包
1

安装 Bun 2.0

使用官方安装脚本快速安装 Bun:

# macOS/Linux 一键安装
curl -fsSL https://bun.com/install | bash

# 验证安装版本(确保≥2.0)
bun --version

# Windows 用户使用 PowerShell
powershell -c "irm bun.com/install.ps1 | iex"

安装完成后,Bun 会自动添加到 PATH。如需手动配置,将 ~/.bun/bin 加入环境变量。

Bun 安装流程示意图
2

初始化项目与类型配置

创建新项目并配置 TypeScript 类型支持:

# 初始化项目
mkdir bun-test-demo && cd bun-test-demo
bun init -y

# 安装 Bun 类型定义(开发依赖)
bun add -d bun-types

创建或更新 tsconfig.json,启用严格模式并配置路径别名:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "types": ["bun-types"],
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"],
      "@test/*": ["test/*"]
    }
  },
  "include": ["src/**/*", "test/**/*"],
  "exclude": ["node_modules"]
}
关键配置:"types": ["bun-types"] 让 TypeScript 识别 Bun 的全局 API 和测试类型。
3

编写第一个测试

创建测试目录结构:

mkdir -p src test
# 创建示例被测试函数
echo 'export const add = (a: number, b: number): number => a + b;' > src/math.ts

编写测试文件 test/math.test.ts

import { test, expect, describe } from "bun:test";
import { add } from "../src/math";

// 基础测试
test("add 函数计算 2+2 等于 4", () => {
  expect(add(2, 2)).toBe(4);
});

test("add 函数处理负数", () => {
  expect(add(-1, -1)).toBe(-2);
  expect(add(-5, 10)).toBe(5);
});

// 使用 describe 组织测试组
describe("add 函数边界测试", () => {
  test("处理极大数值", () => {
    const max = Number.MAX_SAFE_INTEGER;
    expect(() => add(max, 1)).toThrow();
  });

  test("处理小数", () => {
    expect(add(1.5, 2.5)).toBe(4);
  });
});

运行测试:

# 运行所有测试
bun test

# 运行特定文件
bun test test/math.test.ts

# 详细输出模式
bun test --reporter=verbose
测试运行结果示意图
4

快照测试实战

快照测试适用于 UI 组件、复杂对象、API 响应等场景。Bun 的快照测试与 Jest API 兼容:

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

// 测试用户对象结构
test("用户对象快照", () => {
  const user = {
    id: "usr_123",
    name: "张三",
    email: "zhangsan@example.com",
    role: "admin",
    permissions: ["read", "write", "delete"],
    metadata: {
      createdAt: "2026-03-02",
      lastLogin: null,
      settings: { theme: "dark", lang: "zh-CN" }
    }
  };

  expect(user).toMatchSnapshot();
});

// 测试格式化输出
test("日志格式化快照", () => {
  const logEntry = {
    level: "INFO",
    timestamp: "2026-03-02T10:30:00Z",
    message: "用户登录成功",
    context: { userId: "usr_123", ip: "192.168.1.1" }
  };

  const formatted = JSON.stringify(logEntry, null, 2);
  expect(formatted).toMatchSnapshot();
});

首次运行会生成快照文件 test/__snapshots__/math.test.ts.snap

# 运行测试生成快照
bun test

# 查看生成的快照
cat test/__snapshots__/math.test.ts.snap

后续运行会自动比对快照,发现差异时失败:

# 更新快照(谨慎使用)
bun test --update-snapshot

# 或交互模式审查差异
bun test --update-snapshot=interactive
警告:不要盲目更新快照!每次更新前仔细审查差异,确保是预期的变更。
快照测试工作流程图
5

Mock 与生命周期钩子

Bun 提供完整的 Mock 支持和生命周期钩子:

import { test, expect, describe, beforeEach, afterEach, mock } from "bun:test";

describe("API 服务测试", () => {
  // Mock 外部 API
  const fetchMock = mock.fn(() =>
    Promise.resolve({
      ok: true,
      json: () => Promise.resolve({ data: "mocked" })
    })
  );

  // 全局 Mock
  mock.module("undici", () => ({
    fetch: fetchMock
  }));

  // 每个测试前执行
  beforeEach(() => {
    fetchMock.mock.calls = []; // 清空调用记录
    console.log("准备测试环境");
  });

  // 每个测试后执行
  afterEach(() => {
    console.log("清理测试环境");
  });

  test("调用外部 API", async () => {
    const response = await fetchMock("https://api.example.com/data");
    expect(response.ok).toBe(true);
    expect(fetchMock.mock.calls.length).toBe(1);
  });

  // Mock 定时器
  test("定时任务", () => {
    mock.timers.enable();

    const callback = mock.fn();
    setTimeout(callback, 1000);

    mock.timers.tick(1000);
    expect(callback.mock.calls.length).toBe(1);

    mock.timers.disable();
  });
});
Mock 生命周期示意图
6

并发测试与性能优化

Bun 测试支持并发执行,大幅提升大型测试套件速度:

import { test, expect, describe } from "bun:test";

// 标记测试可并发执行
describe("并发测试组", { concurrent: true }, () => {
  test("独立测试 A", async () => {
    await new Promise(r => setTimeout(r, 100));
    expect(1).toBe(1);
  });

  test("独立测试 B", async () => {
    await new Promise(r => setTimeout(r, 100));
    expect(2).toBe(2);
  });

  test("独立测试 C", async () => {
    await new Promise(r => setTimeout(r, 100));
    expect(3).toBe(3);
  });
});

// 跳过特定测试
test.skip("待实现的测试", () => {
  // 暂时跳过
});

// 仅运行此测试(调试用)
test.only("焦点测试", () => {
  // 其他测试会被跳过
});

性能对比命令:

# 串行执行
bun test --no-concurrent

# 并发执行(默认)
bun test --concurrent

# 查看测试耗时
bun test --reporter=verbose --timing
并发测试性能对比图
7

CI/CD 集成实战

在 GitHub Actions 中配置 Bun 测试流水线:

# .github/workflows/test.yml
name: Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Install Bun
        uses: oven-sh/setup-bun@v1
        with:
          bun-version: latest

      - name: Install dependencies
        run: bun install

      - name: Run tests with coverage
        run: bun test --coverage --reporter=junit

      - name: Upload coverage
        uses: codecov/codecov-action@v4
        with:
          files: ./coverage/lcov.info

      - name: Upload test results
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: test-results
          path: junit.xml

bunfig.toml 中配置测试选项:

[test]
# 测试文件匹配模式
root = "test"
pattern = "**/*.test.ts"

# 覆盖率配置
coverage = true
coverage-dir = "./coverage"
coverage-reporters = ["lcov", "text"]

# 超时设置(毫秒)
timeout = 5000

# 并发控制
concurrent = true
CI 流水线配置示意图

常见问题与解决方案

如何迁移现有的 Jest 测试到 Bun?
Bun 测试 API 与 Jest 高度兼容。大多数情况下只需将 import from '@jest/globals' 改为 import from 'bun:test'。对于复杂场景,使用 mock.module() 替代 jest.mock()
快照测试文件应该提交到 Git 吗?
是的,__snapshots__/*.snap 文件应该提交。它们是测试的一部分,用于确保输出一致性。但更新快照时要谨慎审查变更。
如何处理异步测试超时?
bunfig.toml 中调整全局超时,或在单个测试中使用 test('name', fn, { timeout: 10000 }) 设置独立超时。
Bun 测试支持浏览器环境吗?
Bun 测试运行在 Node-like 环境。如需浏览器测试,配合 Playwright 或 Vitest 的浏览器模式。

总结

  • ✓ Bun 2.0 测试框架零配置启动,原生支持 TypeScript
  • ✓ 快照测试工作流与 Jest 兼容,支持交互审查
  • ✓ Mock 系统完整,支持函数、模块、定时器模拟
  • ✓ 并发测试大幅提升执行速度
  • ✓ CI/CD 集成简单,GitHub Actions 原生支持
  • ✓ 覆盖率报告开箱即用,支持多种格式输出
下一步:尝试将现有项目的测试迁移到 Bun,体验 10-100 倍的速度提升!
Bun TypeScript 测试 快照测试 CI/CD
选择栏目
今日简报 播客电台 实战教程 AI挣钱计划 关于我
栏目
全球AI日报国内AI日报全球金融日报国内金融日报全球大新闻日报国内大新闻日报Claude Code 玩法日报OpenClaw 动态日报GitHub 热门项目日报AI工具实战AI应用开发编程实战工作流自动化AI原理图解AI Agent开发AI变现案例库AI工具创收AI内容变现AI接单提效变现前沿研究
我的收藏
播客版
0:00
--:--