Claude CodeでVitest上級テクニックを実践する
Vitestの高度なテスト手法をClaude Codeで効率的に実装する方法を解説。モック戦略、パラメータテスト、カスタムマッチャー、カバレッジ最適化まで紹介します。
Vitestで高品質なテストスイートを構築する
VitestはViteベースの高速テストフレームワークです。Jest互換のAPIに加え、TypeScriptのネイティブサポート、HMR対応の監視モードなど、モダンな開発体験を提供します。Claude Codeは複雑なテストシナリオのコード生成に非常に優れています。
高度なモック戦略
Claude Codeにモジュールモックの設計を依頼しましょう。
> 外部APIクライアントのモックを設計して。
> リクエスト・レスポンスの型チェック付き、エラーケースも含めて。
import { describe, it, expect, vi, beforeEach } from "vitest";
import { UserService } from "./user-service";
import { ApiClient } from "./api-client";
// モジュールモック
vi.mock("./api-client", () => ({
ApiClient: vi.fn().mockImplementation(() => ({
get: vi.fn(),
post: vi.fn(),
put: vi.fn(),
delete: vi.fn(),
})),
}));
describe("UserService", () => {
let service: UserService;
let mockClient: ReturnType<typeof vi.mocked<ApiClient>>;
beforeEach(() => {
vi.clearAllMocks();
mockClient = new ApiClient() as any;
service = new UserService(mockClient);
});
it("ユーザー一覧を取得する", async () => {
const mockUsers = [
{ id: "1", name: "Alice", email: "[email protected]" },
{ id: "2", name: "Bob", email: "[email protected]" },
];
vi.mocked(mockClient.get).mockResolvedValue({ data: mockUsers });
const result = await service.getUsers();
expect(mockClient.get).toHaveBeenCalledWith("/users");
expect(result).toEqual(mockUsers);
});
it("APIエラー時にカスタム例外をスローする", async () => {
vi.mocked(mockClient.get).mockRejectedValue(
new Error("Network Error")
);
await expect(service.getUsers()).rejects.toThrow("ユーザーの取得に失敗しました");
});
});
パラメータテスト(test.each)
同じロジックを複数のパラメータで検証するパターンです。
describe("バリデーション関数", () => {
it.each([
{ input: "[email protected]", expected: true },
{ input: "[email protected]", expected: true },
{ input: "invalid-email", expected: false },
{ input: "@no-local.com", expected: false },
{ input: "no-domain@", expected: false },
{ input: "", expected: false },
])("isValidEmail($input) => $expected", ({ input, expected }) => {
expect(isValidEmail(input)).toBe(expected);
});
it.each`
password | minLength | hasUpper | hasNumber | expected
${"Abc12345"} | ${8} | ${true} | ${true} | ${true}
${"abc12345"} | ${8} | ${false} | ${true} | ${false}
${"short"} | ${8} | ${false} | ${false} | ${false}
${"NoNumbers"} | ${8} | ${true} | ${false} | ${false}
`(
"パスワード強度チェック: $password",
({ password, expected }) => {
expect(isStrongPassword(password)).toBe(expected);
}
);
});
カスタムマッチャーの作成
プロジェクト固有のアサーションを定義できます。
// vitest.setup.ts
import { expect } from "vitest";
expect.extend({
toBeWithinRange(received: number, floor: number, ceiling: number) {
const pass = received >= floor && received <= ceiling;
return {
message: () =>
`expected ${received} to be within range ${floor} - ${ceiling}`,
pass,
};
},
toBeValidDate(received: string) {
const date = new Date(received);
const pass = !isNaN(date.getTime());
return {
message: () => `expected "${received}" to be a valid date string`,
pass,
};
},
toMatchApiResponse(received: unknown) {
const pass =
typeof received === "object" &&
received !== null &&
"data" in received &&
"meta" in received;
return {
message: () => `expected value to match API response shape`,
pass,
};
},
});
// 型定義
declare module "vitest" {
interface Assertion<T = any> {
toBeWithinRange(floor: number, ceiling: number): void;
toBeValidDate(): void;
toMatchApiResponse(): void;
}
}
スナップショットテストの活用
コンポーネントやデータ構造のスナップショットテストです。
import { render } from "@testing-library/react";
describe("UserProfile", () => {
it("プロフィールカードが正しくレンダリングされる", () => {
const { container } = render(
<UserProfile
user={{
id: "1",
name: "テストユーザー",
email: "[email protected]",
role: "admin",
}}
/>
);
expect(container).toMatchSnapshot();
});
it("インラインスナップショットでAPIレスポンスを検証", () => {
const response = transformUserResponse(rawData);
expect(response).toMatchInlineSnapshot(`
{
"displayName": "テストユーザー",
"email": "[email protected]",
"isAdmin": true,
}
`);
});
});
テストカバレッジの最適化
// vitest.config.ts
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
coverage: {
provider: "v8",
reporter: ["text", "json", "html", "lcov"],
include: ["src/**/*.{ts,tsx}"],
exclude: [
"src/**/*.d.ts",
"src/**/*.test.{ts,tsx}",
"src/**/*.stories.{ts,tsx}",
"src/types/**",
"src/**/index.ts",
],
thresholds: {
statements: 80,
branches: 75,
functions: 80,
lines: 80,
},
},
setupFiles: ["./vitest.setup.ts"],
environment: "jsdom",
globals: true,
},
});
非同期テストのパターン
タイマーやイベント待機など、非同期処理のテスト手法です。
describe("非同期処理のテスト", () => {
it("デバウンス関数が正しく動作する", async () => {
vi.useFakeTimers();
const fn = vi.fn();
const debounced = debounce(fn, 300);
debounced("a");
debounced("b");
debounced("c");
expect(fn).not.toHaveBeenCalled();
vi.advanceTimersByTime(300);
expect(fn).toHaveBeenCalledTimes(1);
expect(fn).toHaveBeenCalledWith("c");
vi.useRealTimers();
});
it("リトライロジックが正しく動作する", async () => {
const fn = vi
.fn()
.mockRejectedValueOnce(new Error("1回目失敗"))
.mockRejectedValueOnce(new Error("2回目失敗"))
.mockResolvedValue("成功");
const result = await retry(fn, { maxAttempts: 3, delay: 100 });
expect(result).toBe("成功");
expect(fn).toHaveBeenCalledTimes(3);
});
});
まとめ
Vitestは高速な実行速度とモダンなAPIにより、テスト開発の体験を大きく向上させます。Claude Codeを活用すれば、モック設計、パラメータテスト、カスタムマッチャーなどの高度なテストパターンも素早く実装可能です。
E2Eテストの実装はPlaywright E2Eテスト実践ガイドを、APIモックの詳細はMSW APIモック活用ガイドを参照してください。Vitest公式ドキュメントも確認しておきましょう。
無料PDF: Claude Code はじめてのチートシート
まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。
スパムは送りません。登録情報は厳重に管理します。
Claude Codeを仕事で使える形にしませんか?
無料PDFで基礎を固めたあと、すぐ使えるテンプレート集で試し、必要なら業務自動化や導入相談まで進められます。
この記事を書いた人
Masa
現役DX室長|Claude Code でゼロから多言語AI技術メディア運営中。実務直結の自動化、AI開発相談・研修受付中。
関連書籍・参考図書
この記事のテーマに関連する書籍を楽天ブックスで探せます。
※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。
関連記事
Claude Code/Codexの安全なAgent Harness実装ガイド|権限・検証・ロールバックまで
AIエージェントを安全に動かす足場を、権限設定、実行計画、検証、ロールバックの4層で実装。Claude Code/Codexの実務例付き。
Claude Code サブエージェント活用パターン10選
Claude Code のサブエージェント機能を使いこなす実践パターンを10個紹介。並列処理、専門化、コンテキスト分離で開発効率を倍増させる方法を解説します。
Claude Code Agent SDK入門 ― 自律エージェントを最速で構築する方法
Claude Code Agent SDKを使って自律型AIエージェントを構築する方法を解説。セットアップからツール定義、マルチステップ実行まで実践コード付きで紹介します。