jpskill.com
🛠️ 開発・MCP コミュニティ

tdd

テスト駆動開発(TDD)のワークフローに沿って、最初に失敗するテストを書き、必要最小限のコードを実装し、テストを実行してコミットすることで、機能実装やバグ修正、テストカバレッジ向上を効率的に進めるSkill。

📜 元の英語説明(参考)

Test-driven development workflow — write failing tests first, implement minimum code, run full suite, commit. Use when implementing features, fixing bugs, or adding test coverage. Includes mock bootstrap phase for projects with mockReset:true.

🇯🇵 日本人クリエイター向け解説

一言でいうと

テスト駆動開発(TDD)のワークフローに沿って、最初に失敗するテストを書き、必要最小限のコードを実装し、テストを実行してコミットすることで、機能実装やバグ修正、テストカバレッジ向上を効率的に進めるSkill。

※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o tdd.zip https://jpskill.com/download/9186.zip && unzip -o tdd.zip && rm tdd.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/9186.zip -OutFile "$d\tdd.zip"; Expand-Archive "$d\tdd.zip" -DestinationPath $d -Force; ri "$d\tdd.zip"

完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。

💾 手動でダウンロードしたい(コマンドが難しい人向け)
  1. 1. 下の青いボタンを押して tdd.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → tdd フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-18
取得日時
2026-05-18
同梱ファイル
1

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

TDD 実装スキル

厳密なテスト駆動開発サイクルを強制します: Red → Green → Refactor → Commit。

手順

1. 要件を理解する

タスクの説明を注意深く読みます。以下を特定します:

  • の振る舞いが必要か (入力、出力、副作用)
  • コードベースのどこに属するか (どのワークスペース、どのモジュール)
  • 受け入れ基準 (「完了」とはどういう状態か)

要件が曖昧な場合は、コードを記述する前にユーザーに明確化を求めます。

2. 適切なテストファイルを見つける

プロジェクトの規約に従って、テストファイルを見つけるか作成します:

  • 同じ場所に配置されたテスト: src/foo.tssrc/foo.test.ts
  • テストディレクトリ: src/routes/bar.tssrc/tests/routes/bar.test.ts
  • モノレポ: 各ワークスペースの vitest/jest の設定でテストファイルのパターンを確認します

テストファイルが存在しない場合は、適切なインポートと describe() ブロックを使用して作成します。

3. モック設定の検証 (ブートストラップフェーズ)

テストを記述する前に、モックが正しく動作することを確認します:

  1. テストランナーの設定mockReset/mockClear/restoreMocks の設定を確認します:
grep -rn 'mockReset\|mockClear\|restoreMocks' vitest.config.* jest.config.*

mockReset: true が設定されている場合、モックはテスト間でリセットされます — beforeEach で戻り値を再構成する必要があり、モジュールスコープでは行えません。

  1. テスト対象のモジュールをインポートし、モックが正しく解決されることを検証する最小限のテストを 1 つ記述します:
import { describe, it, expect, vi, beforeEach } from "vitest";

const mocks = vi.hoisted(() => ({
  myDep: vi.fn(),
}));

vi.mock("../path/to/dependency", () => ({
  myDep: (...args: unknown[]) => mocks.myDep(...args),
}));

describe("bootstrap", () => {
  beforeEach(() => {
    mocks.myDep.mockResolvedValue({ ok: true });
  });

  it("mock resolves correctly", async () => {
    const { myDep } = await import("../path/to/dependency");
    expect(await myDep()).toEqual({ ok: true });
  });
});
  1. 実行して、合格することを確認します:
npx vitest run <test-file> --reporter=verbose
  1. その後にのみ、その検証済みのモックパターンに従って、完全なテストスイートの記述に進みます。

なぜ重要なのか: vi.hoisted() はモックの宣言を vi.mock() の巻き上げの上に移動し、一時的なデッドゾーンの問題を回避します。20 個のテストを記述する前に 1 回のモックのラウンドトリップを検証することで、大幅なデバッグ時間を節約できます。

4. 最初に失敗するテストを記述する (Red フェーズ)

モックパターンが機能することを確認したら、ブートストラップテストを削除します。

期待される動作を記述するテストケースを記述します。以下を含めます:

  • ハッピーパス: 有効な入力による通常の操作
  • エッジケース: 空の入力、境界値、欠落しているオプションフィールド
  • エラーケース: 無効な入力、不正なアクセス、欠落しているリソース
npx vitest run <test-file> --reporter=verbose

チェックポイント: すべての新しいテストは失敗する必要があります。合格するものがある場合、テストは新しい動作をテストしていません — それらを修正します。

5. 最小限のコードを実装する (Green フェーズ)

すべてのテストに合格させるための最小限のコードを記述します。以下を行わないでください:

  • テストでカバーされていない機能を追加する
  • 早まって最適化する
  • テストされていないシナリオのエラー処理を追加する
  • 既存のコードをリファクタリングする (次のステップです)
npx vitest run <test-file> --reporter=verbose

チェックポイント: すべてのテスト (新規および既存) は合格する必要があります。

6. 完全なテストスイートを実行する

このステップは決してスキップしないでください:

npx vitest run --reporter=verbose

ファイル外のテストが失敗した場合:

  1. 変更がリグレッションを引き起こしたかどうかを判断します
  2. はいの場合 → 続行する前に修正します
  3. いいえの場合 (既存の失敗) → それをメモしますが、続行します

7. リファクタリング (オプション)

実装がよりクリーンになる可能性がある場合は、テストがグリーンである間にリファクタリングします:

  • 繰り返されるロジックのヘルパーを抽出する
  • ネーミングを改善する
  • 条件を簡略化する

リファクタリング後に完全なスイートを再実行します。

8. 品質ゲート

影響を受けるワークスペースで lint と型チェックを実行します:

npx eslint <changed-files>
npx tsc --noEmit

コミットする前に問題を修正します。

9. コミット

変更したファイルのみをステージングしてコミットします:

type(scope): description

Co-Authored-By: Claude <noreply@anthropic.com>

引数

  • $ARGUMENTS: TDD で実装する内容のオプションの説明
    • 例: /tdd add rate limiting to the search endpoint
    • 空の場合は、ユーザーに何を実装するかを尋ねます

重要なルール

  1. テストの前に実装を記述しないでください — これが TDD の要点です
  2. ステップ 3 をスキップしないでください — 20 個のテストを記述する前に、1 つのテストでモックパターンを検証します
  3. ステップ 6 をスキップしないでください — ファイルだけでなく、完全なスイートが合格する必要があります
  4. テストは正しい理由で失敗する必要があります — インポートの欠落が原因で失敗するテストは、有効な「red」テストではありません
  5. サイクルごとに 1 つの論理的な変更 — 複数の機能を 1 つの TDD サイクルにまとめてバッチ処理しないでください
  6. リファクタリング後にテストが失敗する場合は、最初にテストを疑ってください — テストに誤った前提がある可能性があります

モックパターンのリファレンス

転送パターン (mockReset を乗り越える)

const mockFn = vi.fn();
vi.mock("./dep", () => ({
  dep: (...args: unknown[]) => mockFn(...args),
}));
beforeEach(() => {
  mockFn.mockResolvedValue(defaultResult);
});

カウンターベースのシーケンス (複数クエリ操作)

let callCount = 0;
mockExecute.mockImplementation(async () => {
  callCount++;
  if (callCount === 1) return insertResult;
  if (callCount === 2) return selectResult;
});

globalThis レジストリ (TDZ 回避策)

vi.mock("./dep", () => {
  if (!(globalThis as any).__mocks) (globalThis as any).__mocks = {};
  const m = { dep: vi.fn() };
  (globalThis as any).__mocks.dep = m;
  return { dep: (...a: unknown[]) => m.dep(...a) };
});
// In tests: const mocks = (globalThis as any).__mocks;
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

TDD Implementation Skill

Enforce a strict test-driven development cycle: Red → Green → Refactor → Commit.

Steps

1. Understand the Requirement

Read the task description carefully. Identify:

  • What behavior needs to exist (inputs, outputs, side effects)
  • Where it belongs in the codebase (which workspace, which module)
  • Acceptance criteria (what "done" looks like)

If the requirement is ambiguous, ask the user for clarification before writing any code.

2. Find the Right Test File

Locate or create the test file following project conventions:

  • Colocated tests: src/foo.tssrc/foo.test.ts
  • Test directory: src/routes/bar.tssrc/tests/routes/bar.test.ts
  • Monorepo: Check each workspace's vitest/jest config for test file patterns

If no test file exists, create one with proper imports and describe() block.

3. Verify Mock Setup (Bootstrap Phase)

Before writing any tests, validate that your mocks will work correctly:

  1. Check test runner config for mockReset/mockClear/restoreMocks settings:
grep -rn 'mockReset\|mockClear\|restoreMocks' vitest.config.* jest.config.*

If mockReset: true is set, mocks are reset between tests — you MUST reconfigure return values in beforeEach, not at module scope.

  1. Write ONE minimal test that imports the module under test and verifies mocks resolve correctly:
import { describe, it, expect, vi, beforeEach } from "vitest";

const mocks = vi.hoisted(() => ({
  myDep: vi.fn(),
}));

vi.mock("../path/to/dependency", () => ({
  myDep: (...args: unknown[]) => mocks.myDep(...args),
}));

describe("bootstrap", () => {
  beforeEach(() => {
    mocks.myDep.mockResolvedValue({ ok: true });
  });

  it("mock resolves correctly", async () => {
    const { myDep } = await import("../path/to/dependency");
    expect(await myDep()).toEqual({ ok: true });
  });
});
  1. Run it and confirm it passes:
npx vitest run <test-file> --reporter=verbose
  1. Only then proceed to write the full test suite following that proven mock pattern.

Why this matters: vi.hoisted() moves mock declarations above vi.mock() hoisting, avoiding temporal dead zone issues. Validating one mock round-trip before writing 20 tests saves significant debugging time.

4. Write Failing Tests FIRST (Red Phase)

Remove the bootstrap test once you've confirmed the mock pattern works.

Write test cases that describe the expected behavior. Include:

  • Happy path: Normal operation with valid inputs
  • Edge cases: Empty inputs, boundary values, missing optional fields
  • Error cases: Invalid inputs, unauthorized access, missing resources
npx vitest run <test-file> --reporter=verbose

Checkpoint: All new tests MUST fail. If any pass, the tests are not testing new behavior — revise them.

5. Implement Minimum Code (Green Phase)

Write the minimum code to make all tests pass. Do NOT:

  • Add features not covered by tests
  • Optimize prematurely
  • Add error handling for untested scenarios
  • Refactor existing code (that's the next step)
npx vitest run <test-file> --reporter=verbose

Checkpoint: All tests (new and existing) MUST pass.

6. Run the FULL Test Suite

Never skip this step:

npx vitest run --reporter=verbose

If any tests outside your file fail:

  1. Determine if your change caused the regression
  2. If yes → fix it before proceeding
  3. If no (pre-existing failure) → note it but continue

7. Refactor (Optional)

If the implementation can be cleaner, refactor now while tests are green:

  • Extract helpers for repeated logic
  • Improve naming
  • Simplify conditionals

Re-run the full suite after any refactor.

8. Quality Gates

Run lint and type checks on affected workspaces:

npx eslint <changed-files>
npx tsc --noEmit

Fix any issues before committing.

9. Commit

Stage only the files you changed and commit:

type(scope): description

Co-Authored-By: Claude <noreply@anthropic.com>

Arguments

  • $ARGUMENTS: Optional description of what to implement via TDD
    • Example: /tdd add rate limiting to the search endpoint
    • If empty, ask the user what to implement

Key Rules

  1. Never write implementation before tests — this is the whole point of TDD
  2. Never skip step 3 — validate your mock pattern with ONE test before writing 20
  3. Never skip step 6 — the full suite must pass, not just your file
  4. Tests should fail for the RIGHT reason — a test that fails because of a missing import isn't a valid "red" test
  5. One logical change per cycle — don't batch multiple features into one TDD cycle
  6. When tests fail after refactor, question the TESTS first — they may have bad assumptions

Mock Patterns Reference

Forwarding Pattern (survives mockReset)

const mockFn = vi.fn();
vi.mock("./dep", () => ({
  dep: (...args: unknown[]) => mockFn(...args),
}));
beforeEach(() => {
  mockFn.mockResolvedValue(defaultResult);
});

Counter-Based Sequencing (multi-query operations)

let callCount = 0;
mockExecute.mockImplementation(async () => {
  callCount++;
  if (callCount === 1) return insertResult;
  if (callCount === 2) return selectResult;
});

globalThis Registry (TDZ workaround)

vi.mock("./dep", () => {
  if (!(globalThis as any).__mocks) (globalThis as any).__mocks = {};
  const m = { dep: vi.fn() };
  (globalThis as any).__mocks.dep = m;
  return { dep: (...a: unknown[]) => m.dep(...a) };
});
// In tests: const mocks = (globalThis as any).__mocks;