名称: Bun 测试模拟 描述: 用于在Bun测试中模拟函数、spyOn、mock.module、实现和测试双打。 版本: 1.0.0
Bun 测试模拟
Bun 提供与Jest兼容的模拟功能,包括 mock()、spyOn() 和模块模拟。
模拟函数
import { test, expect, mock } from "bun:test";
// 创建模拟函数
const fn = mock(() => "original");
test("模拟函数", () => {
fn("arg1", "arg2");
expect(fn).toHaveBeenCalled();
expect(fn).toHaveBeenCalledTimes(1);
expect(fn).toHaveBeenCalledWith("arg1", "arg2");
});
jest.fn() 兼容性
import { test, expect, jest } from "bun:test";
const fn = jest.fn(() => "value");
test("jest.fn 工作", () => {
const result = fn();
expect(result).toBe("value");
expect(fn).toHaveBeenCalled();
});
模拟返回值
const fn = mock();
// 一次返回值
fn.mockReturnValueOnce("first");
fn.mockReturnValueOnce("second");
// 永久返回值
fn.mockReturnValue("default");
// Promise 返回值
fn.mockResolvedValue("resolved");
fn.mockResolvedValueOnce("once");
fn.mockRejectedValue(new Error("fail"));
fn.mockRejectedValueOnce(new Error("once"));
模拟实现
const fn = mock();
// 设置实现
fn.mockImplementation((x) => x * 2);
// 一次实现
fn.mockImplementationOnce((x) => x * 10);
// 链式实现
fn
.mockImplementationOnce(() => "first")
.mockImplementationOnce(() => "second")
.mockImplementation(() => "default");
监视方法
import { test, expect, spyOn } from "bun:test";
const obj = {
method: () => "original",
};
test("监视方法", () => {
const spy = spyOn(obj, "method");
obj.method();
expect(spy).toHaveBeenCalled();
expect(obj.method()).toBe("original"); // 仍然工作
// 覆盖实现
spy.mockImplementation(() => "mocked");
expect(obj.method()).toBe("mocked");
// 恢复
spy.mockRestore();
expect(obj.method()).toBe("original");
});
模拟模块
import { test, expect, mock } from "bun:test";
// 模拟整个模块
mock.module("./utils", () => ({
add: mock(() => 999),
subtract: mock(() => 0),
}));
// 现在导入使用模拟版本
import { add } from "./utils";
test("模拟模块", () => {
expect(add(1, 2)).toBe(999);
});
模拟 Node 模块
mock.module("axios", () => ({
default: {
get: mock(() => Promise.resolve({ data: "mocked" })),
post: mock(() => Promise.resolve({ data: "created" })),
},
}));
使用工厂模拟
mock.module("./config", () => {
return {
API_URL: "http://test.local",
DEBUG: true,
};
});
模拟断言
const fn = mock();
fn("a", "b");
fn("c", "d");
// 调用计数
expect(fn).toHaveBeenCalled();
expect(fn).toHaveBeenCalledTimes(2);
// 调用参数
expect(fn).toHaveBeenCalledWith("a", "b");
expect(fn).toHaveBeenLastCalledWith("c", "d");
expect(fn).toHaveBeenNthCalledWith(1, "a", "b");
// 返回值
fn.mockReturnValue("result");
fn();
expect(fn).toHaveReturned();
expect(fn).toHaveReturnedWith("result");
expect(fn).toHaveReturnedTimes(1);
模拟属性
const fn = mock(() => "value");
fn("arg1");
fn("arg2");
// 访问调用信息
fn.mock.calls; // [["arg1"], ["arg2"]]
fn.mock.results; // [{ type: "return", value: "value" }, ...]
fn.mock.lastCall; // ["arg2"]
// 清除历史
fn.mockClear(); // 清除调用,保留实现
fn.mockReset(); // 清除调用 + 实现
fn.mockRestore(); // 恢复原始(用于监视)
常见模式
模拟 Fetch
import { test, expect, spyOn } from "bun:test";
test("模拟 fetch", async () => {
const spy = spyOn(global, "fetch").mockResolvedValue(
new Response(JSON.stringify({ data: "mocked" }))
);
const response = await fetch("/api/data");
const json = await response.json();
expect(json.data).toBe("mocked");
expect(spy).toHaveBeenCalledWith("/api/data");
spy.mockRestore();
});
模拟 Console
test("模拟 console", () => {
const spy = spyOn(console, "log");
console.log("test message");
expect(spy).toHaveBeenCalledWith("test message");
spy.mockRestore();
});
模拟类方法
class UserService {
async getUser(id: string) {
// 真实实现
}
}
test("模拟类方法", () => {
const service = new UserService();
const spy = spyOn(service, "getUser").mockResolvedValue({
id: "1",
name: "Test User",
});
const user = await service.getUser("1");
expect(user.name).toBe("Test User");
expect(spy).toHaveBeenCalledWith("1");
});
常见错误
| 错误 | 原因 | 修复 |
|---|---|---|
Cannot spy on undefined |
属性不存在 | 检查属性名称 |
Not a function |
尝试模拟非函数 | 使用正确的模拟方法 |
Already mocked |
重复模拟 | 先使用 mockRestore |
Module not found |
模块路径错误 | 检查 mock.module 中的路径 |
何时加载参考文献
加载 references/mock-api.md 当:
- 完整模拟/监视 API 参考
- 高级模拟模式
加载 references/module-mocking.md 当:
- 复杂模块模拟
- 提升行为细节