Skip to main content
模拟会使用受控的实现替换依赖项。Bun 支持函数模拟、间谍以及模块模拟。

基础函数模拟

使用 mock 函数创建模拟。
test.ts

Jest 兼容性

你也可以像在 Jest 中一样使用 jest.fn()。它的行为完全相同。
test.ts

模拟函数属性

mock() 返回一个带有附加属性的新函数。
test.ts

可用属性和方法

模拟函数实现了以下属性和方法:

实际示例

基础模拟用法

test.ts

动态模拟实现

test.ts

异步模拟

test.ts

使用 spyOn() 创建间谍

使用 spyOn() 跟踪函数调用,而不将其替换为模拟函数。你可以将间谍传给 .toHaveBeenCalled() 和 .toHaveBeenCalledTimes()。
test.ts

高级间谍用法

test.ts

使用 mock.module() 进行模块模拟

使用 mock.module(path: string, callback: () => Object) 覆盖模块的行为。
test.ts
与 Bun 其他部分一样,模块模拟同时支持 import 和 require。

重写已导入模块

调用 mock.module() 会覆盖模块,即使该模块已经被导入。
test.ts
当工厂函数返回一个仍处于待定状态的 Promise 时,Bun 会在该 Promise 完成后更新已导入的模块。在这种情况下,mock.module() 会返回一个在更新完成后解析的 Promise;否则,它会返回 undefined。在测试或钩子中使用 await mock.module(...) 可以同时处理这两种情况。在测试文件的顶层,Bun 会等待待定的模块模拟完成后再运行文件中的测试。
test.ts
fixture.json

提升与预加载

为了确保模块在导入之前已被模拟,请使用 --preload 在测试运行前加载模拟模块。
my-preload.ts
terminal
为了避免每次运行测试时都输入 --preload,请将其添加到 bunfig.toml 中:
bunfig.toml

模块模拟最佳实践

何时使用预加载

模拟已导入的模块会更新模块缓存,因此任何导入该模块的内容都会获取模拟版本。不过,Bun 已经执行了原始模块,因此其副作用也已经发生。 若要完全避免执行原始模块,请使用 --preload 在测试运行前加载模拟模块。

实际模块模拟示例

api-client.test.ts

模拟外部依赖

database.test.ts

全局模拟函数

清除所有模拟

mock.clearAllMocks() 会重置每个模拟的 .mock.calls、.mock.instances、.mock.contexts 和 .mock.results 属性。与 mock.restore() 不同,它不会恢复原始实现:
test.ts

重置所有模拟

jest.resetAllMocks()(及其别名 vi.resetAllMocks())会对每个模拟调用 mockFn.mockReset()。除了 clearAllMocks() 的操作外,它还会丢弃通过 mockImplementation()、mockReturnValue() 等方法设置的实现。它不会恢复间谍的原始实现:
test.ts

恢复所有模拟

mock.restore() 一次性恢复所有模拟,而不必分别对每个模拟调用 mockFn.mockRestore()。它不会重置通过 mock.module() 覆盖的模块。
test.ts
在 afterEach 块或测试预加载脚本中调用 mock.restore(),这样就不必在每个测试中重复清理操作。

Vitest 兼容性

为方便移植 Vitest 编写的测试,Bun 提供了 vi 对象作为 Jest 模拟 API 部分的别名:
test.ts
你可以直接移植 Vitest 测试,无需重写模拟函数。

实现细节

缓存交互

模块模拟会与 ESM 和 CommonJS 模块缓存交互。

惰性求值

Bun 仅在导入或 require 模块时才会执行模拟工厂回调。

路径解析

Bun 以解析 import 的相同方式解析模块说明符,支持:
  • 相对路径('./module')
  • 绝对路径('/path/to/module')
  • 包名('lodash')

导入时机影响

  • 在首次导入前模拟:原模块不会执行副作用
  • 在导入后模拟:原模块副作用已经发生
因此,对于需要阻止副作用的模拟,请使用 --preload。

实时绑定

被模拟的 ESM 模块会维护实时绑定,因此更改模拟内容会更新所有现有导入。

高级模式

工厂函数

test.ts

条件式模拟

test.ts

模拟清理模式

test.ts

最佳实践

保持模拟简单

test.ts

使用类型安全的模拟

测试模拟行为

test.ts

备注

自动模拟

Bun 不支持 __mocks__ 目录或自动模拟。如果这阻碍了你迁移到 Bun,请提交 issue。

ESM 与 CommonJS

ESM 和 CommonJS 模块的模块模拟实现方式不同。对于 ES 模块,Bun 会修补 JavaScriptCore,以便在运行时覆盖导出值,并递归更新实时绑定。