运行时包管理器打包器测试运行器代码检查格式化指南参考博客反馈

使用通配符模式有选择地并发运行测试

设置通配符模式以决定来自哪些文件的哪些测试并行运行

bunfig.toml 中的 concurrentTestGlob 选项会在文件名匹配通配符模式的文件中并发运行测试。

项目结构

项目结构
my-project/
├── bunfig.toml
├── tests/
│   ├── unit/
│   │   ├── math.test.ts          # 顺序执行
│   │   └── utils.test.ts         # 顺序执行
│   └── integration/
│       ├── concurrent-api.test.ts     # 并发执行
│       └── concurrent-database.test.ts # 并发执行

配置

配置 bunfig.toml,以并发运行带有“concurrent-”前缀的测试文件:

bunfig.toml
[test]
# 并发执行所有以 "concurrent-" 开头的测试文件
concurrentTestGlob = "**/concurrent-*.test.ts"

测试文件

单元测试(顺序执行)

共享状态或依赖执行顺序的测试应保持顺序执行:

tests/unit/math.test.ts
import { test, expect } from "bun:test";

// 这些测试默认顺序执行
let sharedState = 0;

test("addition", () => {
  sharedState = 5 + 3;
  expect(sharedState).toBe(8);
});

test("uses previous state", () => {
  // 该测试依赖于前一个测试的状态
  expect(sharedState).toBe(8);
});

集成测试(并发执行)

匹配通配符模式的文件中的测试自动并发运行:

tests/integration/concurrent-api.test.ts
import { test, expect } from "bun:test";

// 由于文件名匹配通配符模式,这些测试会自动并发执行。
// 在匹配 concurrentTestGlob 时,使用 test() 等同于 test.concurrent()。
// 每个测试都是独立的,可以并行运行。

test("fetch user data", async () => {
  const response = await fetch("/api/user/1");
  expect(response.ok).toBe(true);
});

// 也可以显式使用 test.concurrent() 标记为并发执行
test.concurrent("fetch posts", async () => {
  const response = await fetch("/api/posts");
  expect(response.ok).toBe(true);
});

// 也可以显式使用 test.serial() 标记为顺序执行
test.serial("fetch comments", async () => {
  const response = await fetch("/api/comments");
  expect(response.ok).toBe(true);
});

运行测试

terminal
# 运行所有测试 - concurrent-*.test.ts 文件将并发运行
bun test

# 覆盖设置:强制所有测试并发运行
# 注意:此选项会覆盖 bunfig.toml,所有测试无视通配符都并发运行
bun test --concurrent

# 只运行单元测试(顺序执行)
bun test tests/unit

# 只运行集成测试(由于通配符模式并发执行)
bun test tests/integration

优点

  1. 渐进式迁移:一次重命名一个文件,将其迁移到并发执行
  2. 组织清晰:文件名会告诉你该文件中的测试如何运行
  3. 性能提升:独立的集成测试并行运行时完成得更快
  4. 安全性:单元测试在需要时保持串行运行

迁移策略

迁移现有测试到并发执行:

  1. 从相互独立的集成测试开始 - 这些测试通常不会共享状态
  2. 重命名文件以匹配 glob 模式:mv api.test.ts concurrent-api.test.ts
  3. 运行 bun test - 检查竞态条件以及不稳定或意外的失败
  4. 逐个文件继续迁移稳定的测试

建议

  • 使用描述性前缀:concurrent-、parallel-、async-
  • 将相关的顺序测试放在同一目录中
  • 通过注释说明某些测试必须保持顺序执行的原因
  • 在顺序执行的文件中使用 test.concurrent() 进行细粒度控制 (在与 concurrentTestGlob 匹配的文件中,普通的 test() 已会并发运行)

多个模式

concurrentTestGlob 也接受多个模式:

bunfig.toml
[test]
concurrentTestGlob = [
  "**/integration/*.test.ts",
  "**/e2e/*.test.ts",
  "**/concurrent-*.test.ts"
]

匹配任意这些模式的文件中的测试将并发运行:

  • 所有 integration/ 目录下的测试
  • 所有 e2e/ 目录下的测试
  • 项目中任意位置所有以 concurrent- 前缀命名的测试文件。