bun-test-mocking について
Bunでテストを行う開発者向けのモック機能のスキルです。関数やメソッド、モジュールのモックと、呼び出しの検証方法を扱います。
主な機能
- 01モック関数と戻り値の設定
- 02関数の実装の置き換え
- 03オブジェクトメソッドのスパイ
- 04モジュールとNodeモジュールのモック
- 05呼び出し情報と結果の確認
活用シーン
- 01非同期関数に一度限りの戻り値を設定
- 02メソッドの呼び出し回数と引数を検証
- 03テスト中に依存モジュールを分離
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ secondsky/ claude-skills --skill bun-test-mockingインストール後、Claude Code で/bun-test-mockingを入力して読み込まれたか確認します。
詳細
Bun テストのモック
Bun では、mock()、spyOn()、モジュールのモックを使って、Jest 互換のモックを利用できます。
モック関数
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 対応