mcpField
B
bun-test-mocking

bun-test-mocking

github.com/secondsky测试与质量240412 次安装5 周前更新
代码仓库

关于 bun-test-mocking

面向使用 Bun 的测试开发者的 Mocking 技能,介绍函数、方法和模块模拟及相关断言。

主要功能

  1. 01创建 Mock 函数并设置返回值
  2. 02替换函数实现
  3. 03监视对象方法
  4. 04模拟模块与 Node 模块
  5. 05检查调用记录和结果

适用场景

  1. 01为异步函数设置一次性返回值
  2. 02验证方法调用次数与参数
  3. 03隔离依赖模块进行测试

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/secondsky/claude-skills --skill bun-test-mocking

安装后在 Claude Code 中输入/bun-test-mocking确认已加载。

详细介绍

Bun 测试模拟

Bun 提供与 Jest 兼容的模拟功能,包括 mock()、spyOn() 和模块模拟。

模拟函数

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

// Create mock function
const fn = mock(() => "original");

test("mock function", () => {
  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 works", () => {
  const result = fn();
  expect(result).toBe("value");
  expect(fn).toHaveBeenCalled();
});

模拟返回值

const fn = mock();

// Return value once
fn.mockReturnValueOnce("first");
fn.mockReturnValueOnce("second");

// Permanent return value
fn.mockReturnValue("default");

// Promise returns
fn.mockResolvedValue("resolved");
fn.mockResolvedValueOnce("once");
fn.mockRejectedValue(new Error("fail"));
fn.mockRejectedValueOnce(new Error("once"));

模拟实现

const fn = mock();

// Set implementation
fn.mockImplementation((x) => x * 2);

// One-time implementation
fn.mockImplementationOnce((x) => x * 10);

// Chain implementations
fn
  .mockImplementationOnce(() => "first")
  .mockImplementationOnce(() => "second")
  .mockImplementation(() => "default");

监视方法

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

const obj = {
  method: () => "original",
};

test("spy on method", () => {
  const spy = spyOn(obj, "method");

  obj.method();

  expect(spy).toHaveBeenCalled();
  expect(obj.method()).toBe("original"); // Still works

  // Override implementation
  spy.mockImplementation(() => "mocked");
  expect(obj.method()).toBe("mocked");

  // Restore
  spy.mockRestore();
  expect(obj.method()).toBe("original");
});

模拟模块

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

// Mock entire module
mock.module("./utils", () => ({
  add: mock(() => 999),
  subtract: mock(() => 0),
}));

// Now imports use mocked version
import { add } from "./utils";

test("mocked module", () => {
  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");

// Call count
expect(fn).toHaveBeenCalled();
expect(fn).toHaveBeenCalledTimes(2);

// Call arguments
expect(fn).toHaveBeenCalledWith("a", "b");
expect(fn).toHaveBeenLastCalledWith("c", "d");
expect(fn).toHaveBeenNthCalledWith(1, "a", "b");

// Return values
fn.mockReturnValue("result");
fn();
expect(fn).toHaveReturned();
expect(fn).toHaveReturnedWith("result");
expect(fn).toHaveReturnedTimes(1);

模拟属性

const fn = mock(() => "value");

fn("arg1");
fn("arg2");

// Access call info
fn.mock.calls;        // [["arg1"], ["arg2"]]
fn.mock.results;      // [{ type: "return", value: "value" }, ...]
fn.mock.lastCall;     // ["arg2"]

// Clear history
fn.mockClear();       // Clear calls, keep implementation
fn.mockReset();       // Clear calls + implementation
fn.mockRestore();     // Restore original (for spies)

常见模式

模拟 Fetch
import { test, expect, spyOn } from "bun:test";

test("mock 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("mock console", () => {
  const spy = spyOn(console, "log");

  console.log("test message");

  expect(spy).toHaveBeenCalledWith("test message");
  spy.mockRestore();
});
模拟类方法
class UserService {
  async getUser(id: string) {
    // Real implementation
  }
}

test("mock class method", () => {
  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:

  • 需要进行复杂的模块模拟
  • 需要了解提升行为的细节

评论

支持 Markdown