基础函数模拟
使用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
import 和 require。
重写已导入模块
调用mock.module() 会覆盖模块,即使该模块已经被导入。
test.ts
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
实现细节
缓存交互
模块模拟会与 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。