moai-workflow-tdd について
moai-workflow-tdd は、新機能を開発するためのテスト駆動開発スキルです。RED-GREEN-REFACTOR のサイクルで作業を進め、実装前に失敗するテストで振る舞いを定義します。
主な機能
- 01RED-GREEN-REFACTOR 開発サイクル
- 02実装前の振る舞いテスト
- 03テストを通すための最小限の実装
- 04テストを継続実行するリファクタリング
- 05カバレッジと品質の検証
活用シーン
- 01契約に基づく新しい API エンドポイントの開発
- 02振る舞いが定義された UI コンポーネントの構築
- 03小さなテストファーストのサイクルで機能を追加
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ modu-ai/ moai-adk --skill moai-workflow-tddインストール後、Claude Code で/moai-workflow-tddを入力して読み込まれたか確認します。
同梱ファイルreferences/examples.mdreferences/reference.md
詳細
テスト駆動開発(TDD)ワークフロー
開発モードの設定(重要)
[NOTE] このワークフローは .moai/config/sections/quality.yaml に基づいて選択されます。
constitution:
development_mode: tdd # or ddd
このワークフローを使用する場合:
development_mode: tdd→ TDD を使用します(このワークフローがデフォルトです)development_mode: ddd→ 代わりに DDD を使用します(moai-workflow-ddd)
主な違い:
- TDD(デフォルト):既存プロジェクトの事前の RED 分析を含め、すべての作業でテストファースト開発を行います
- DDD:テストカバレッジが最小限の既存コードベースで、特性テストファーストで進めます
クイックリファレンス
テスト駆動開発は、実装前にテストで期待される動作を定義する、新しい機能を作成するための規律あるアプローチです。
基本サイクル — RED-GREEN-REFACTOR:
- RED:望ましい動作を定義する失敗するテストを書きます
- GREEN:テストに合格するための最小限のコードを書きます
- REFACTOR:テストを成功させたまま、コード構造を改善します
TDD を使用する場合:
- 新しい機能をゼロから作成するとき
- 既存の依存関係がない独立したモジュールを構築するとき
- 動作の仕様が開発を主導するとき
- 明確な契約を持つ新しい API エンドポイントを作成するとき
- 動作が定義された新しい UI コンポーネントを作成するとき
- グリーンフィールドプロジェクト(まれです。通常はハイブリッドの方が適しています)
TDD を使用しない場合:
- 既存のコードをリファクタリングするとき(代わりに DDD を使用します)
- 動作の維持が主な目的であるとき
- テストカバレッジがないレガシーコードベースの場合(まず DDD を使用します)
- 既存ファイルを変更するとき(ハイブリッドモードを検討します)
基本理念
TDD と DDD の比較
TDD のアプローチ:
- サイクル:RED-GREEN-REFACTOR
- 目標:テストを通じて新しい機能を作成します
- 開始地点:コードが存在しません
- テストの種類:期待される動作を定義する仕様テスト
- 結果:テストカバレッジのある、新たに動作するコード
DDD のアプローチ:
- サイクル:ANALYZE-PRESERVE-IMPROVE
- 目標:動作を変更せずに構造を改善します
- 開始地点:動作が定義された既存のコード
- テストの種類:現在の動作を記録する特性テスト
- 結果:動作は同一のまま、構造が改善されたコード
テストファーストの原則
TDD の黄金律は、実装コードより先にテストを書かなければならないことです。
- テストが契約を定義します
- テストが期待される動作を記録します
- テストがリグレッションを即座に検出します
- テスト要件に基づいて実装を進めます
実装ガイド
フェーズ 1:RED — 失敗するテストを書く
RED フェーズでは、失敗するテストを通じて望ましい動作を定義します。
効果的なテストを書く
実装コードを書く前に:
- 要件を明確に理解します
- 期待される動作をテスト形式で定義します
- 一度に 1 つずつテストを書きます
- テストの対象を絞り、具体的にします
- 動作を記録する、説明的なテスト名を使用します
テストの構成
Arrange-Act-Assert パターンに従います。
- Arrange:テストデータと依存関係を設定します
- Act:テスト対象のコードを実行します
- Assert:期待される結果を検証します
検証
テストは最初に失敗しなければなりません。
- テストが実際に何かを検証していることを確認します
- 偶然テストに合格していないことを確認します
- 現状と望ましい状態のギャップを記録します
フェーズ 2:GREEN — テストに合格させる
GREEN フェーズでは、テストを満たすための最小限のコードを書きます。
最小限の実装
テストに合格するために必要なコードだけを書きます。
- 過剰に設計しないでください
- テストで必要とされていない機能を追加しないでください
- 完璧さではなく、正しさに注力します
- 必要であれば値をハードコードします(後でリファクタリングします)
検証
テストを実行して、合格することを確認します。
- すべてのアサーションが成功する必要があります
- ほかのテストが失敗してはいけません
- 実装がテスト要件を満たしていることを確認します
フェーズ 3:REFACTOR — コードを改善する
REFACTOR フェーズでは、動作を維持しながらコードの品質を改善します。
安全なリファクタリング
テストが成功している状態を安全網として:
- 重複を取り除きます
- 命名と可読性を改善します
- メソッドやクラスを抽出します
- 適切な場合はデザインパターンを適用します
継続的な検証
各リファクタリングのステップの後に、次を行います。
- すべてのテストを実行する
- テストが1つでも失敗した場合は、直ちに元に戻す
- テストが通ったらコミットする
TDD ワークフローの実行
標準的な TDD セッション
manager-develop を通じて TDD を実行する場合:
ステップ 1 - 要件を理解する:
- 機能の範囲について SPEC ドキュメントを読む
- 受け入れ基準からテストケースを特定する
- テストの実装順序を計画する
ステップ 2 - RED フェーズ:
- 最初の失敗するテストを書く
- 正しい理由でテストが失敗することを確認する
- 期待される動作を記録する
ステップ 3 - GREEN フェーズ:
- 最小限の実装を書く
- テストを実行して成功することを確認する
- 次のテストに進む
ステップ 4 - REFACTOR フェーズ:
- コードの改善点を確認する
- テストをセーフティネットとしてリファクタリングを適用する
- 整理されたコードをコミットする
ステップ 5 - 繰り返す:
- RED-GREEN-REFACTOR サイクルを続ける
- すべての要件が実装されるまで続ける
- すべての受け入れ基準を満たすまで続ける
TDD ループのパターン
複数のテストケースが必要な機能の場合:
- 事前にすべてのテストケースを特定する
- 依存関係と複雑さに基づいて優先順位を付ける
- 各テストケースで RED-GREEN-REFACTOR を実行する
- 累積するテストスイートを維持する
品質指標
TDD の成功基準
テストカバレッジ(必須):
- コミットごとに最低 80% のカバレッジ
- 新しいコードでは 90% を推奨
- すべての公開インターフェースをテストする
コード品質(目標):
- すべてのテストが成功する
- 実装後にテストを書かない
- 動作を明確に記述したテスト名を付ける
- テストを満たす最小限の実装にする
TDD に特化した TRUST 検証
TDD に重点を置いて TRUST 5 フレームワークを適用します。
- テスト済み:テストファーストのアプローチによりカバレッジを確保する
- 可読性:テストで期待される動作を記述する
- 統一性:周囲のコードとスタイルおよび構造を統一する
- セキュリティ:実装前にセキュリティテストを書く
- 追跡可能性:テストの失敗により、原因を特定できる即時のフィードバックが得られる
統合ポイント
DDD ワークフローとの連携
TDD と DDD は相互に補完します。
- 新しいコードには TDD
- 既存コードのリファクタリングには DDD
- ハイブリッドモードでは両方のアプローチを組み合わせる
テストワークフローとの連携
TDD はテストワークフローと統合します。
- 仕様テストを使用する
- カバレッジツールと統合する
- テスト品質のためのミューテーションテストをサポートする
品質フレームワークとの連携
TDD の出力は品質評価に利用されます。
- カバレッジ指標を追跡する
- 変更に対して TRUST 5 検証を行う
- 品質ゲートによって標準を徹底する
トラブルシューティング
よくある問題
テストが複雑すぎる:
- 小さく、焦点を絞ったテストに分割する
- 一度に1つの動作をテストする
- 複雑なセットアップにはテストフィクスチャを使用する
実装が急速に大きくなる:
- テストしていない機能を実装したい衝動を抑える
- 新しい機能では RED フェーズに戻る
- GREEN フェーズを最小限に保つ
リファクタリングでテストが失敗する:
- 直ちに元に戻す
- より小さなステップでリファクタリングする
- テストが実装ではなく動作を検証していることを確認する
復旧手順
TDD の規律が崩れた場合:
- 作業を止めて現在の状態を評価する
- 既存コードの特性評価テストを書く
- 残りの機能について TDD を再開する
- ハイブリッドモードへの切り替えを検討する
バージョン:1.0.0 ステータス:有効
よくある正当化
| 正当化 | 実際のところ |
|---|---|
| 「実装が動いてからテストを追加します」 | 後付けのテストで検証できるのは、コードが何をするかであり、何をすべきかではありません。RED フェーズで検出できるバグを見逃します。 |
| 「既存のテストでこのケースはカバーされています」 | 既存のテストが検証するのは従来の動作です。新しい動作には、まずそれに対応する失敗するテストが必要です。 |
| 「この関数は単純すぎてテストする必要がありません」 | 単純な関数にも、やがて複雑さが積み重なります。テストがあれば、動作がずれてしまう前に期待される動作を記録できます。 |
| 「ターミナルで手動テストしました」 | 手動での確認は記録に残りません。翌日の変更で、何の通知もなく契約が破られる可能性があります。 |
| 「テストには複雑なモックが必要です」 | テストを書くのが難しいなら、コードを理解するのも難しいということです。まず設計をリファクタリングしてください。 |
| 「テストを書くと作業が遅くなります」 | テストファーストなら、修正コストが最も低い早い段階で設計上の問題が明らかになります。 |
| 「作業を進めるために、今回はリファクタリングを省略します」 | リファクタリングを省くと、問題が積み重なります。次のサイクルは、より悪い状態から始まります。 |
DRY より DAMP:テストコードでは、Don't Repeat Yourself(繰り返しを避けること)より、Descriptive And Meaningful Phrases(説明的で意味のある表現)を優先してください。意図を明確にするためのテスト内の重複は、意図を隠してしまう抽象化よりも望ましいです。
ビヨンセ・ルール:気に入ったなら、テストを用意しておくべきです。CI で検証されない動作は、いずれ警告なしに壊れます。
危険な兆候
- テストファイルと同じコミットで実装ファイルが作成されている(RED フェーズが省略されています)
- テスト名が動作ではなく実装を説明している(
test_function_returns_trueではなくtest_user_login_rejects_expired_tokenのような名前にします) - 新しいファイル内のすべてのテストが初回実行で成功する(RED フェーズの記録がありません)
- 機能がすでにマージされた後に、「テストを追加」とコミットメッセージに記載されている
- テストスイートに、テスト対象のコードのモックが含まれている(協調するオブジェクトではなく、実装をモックしています)
- 新機能を追加したコミットでカバレッジが低下している
検証
- Git 履歴に、実装コミットより前の失敗するテストのコミット、または同じコミット内の RED の証拠がある
- テスト名が関数の説明ではなく、動作仕様として読める
- 新しい公開関数ごとに、対応するテストケースが少なくとも 1 つある
- テストスイート全体が成功する(コマンドの出力を貼り付ける)
- 変更したファイルのカバレッジを測定し、報告する(ツールの出力を示す)
- この変更で
skip、xit、または無効化されたテストを追加していない - リファクタリングフェーズを実行したか、不要であることを明示的に正当化した
テストファーストの不正防止
[ZONE:Evolvable] [HARD] 上記の「危険な兆候」と「検証」のチェックリストは、アドバイザリー(進化可能)ブロック内にあり、完了ゲートでは使用されません。このセクションでは、これらを完了マトリックスでテストファーストを反証可能にする、強制的な 2 つの不変条件に引き上げます。
- 不変条件 i — RED の失敗出力は完了の必須証拠です。 RED の失敗するテストの出力(実装によって成功するようになる前に取得した、失敗するテスト実行の出力そのもの)を確認し、実行フェーズの完了証拠として提示しなければなりません。実行時にこの出力を生成できない場合、RED が省略されたことになり、問題なく完了したとは報告できません。
- 不変条件 ii — 失敗するテストより先に記述された実装は削除し、テストファーストで導出し直さなければなりません。 失敗するテストが存在する前に記述された実装コードは、すべて削除し、失敗するテストから導出し直さなければなりません(RED の後に GREEN)。「実装をすでに書いたので、テストは初回実行で成功します」は、この不変条件が禁じるまさにその失敗パターンです。これはテストファーストではなく、テスト後であり、証拠として示せる RED の出力(不変条件 i)が残りません。
この 2 つの不変条件によって、反証可能性の空白が埋まります。これらがなければ、RED の証拠がなくても、自己検証マトリックスを完全に成功した状態で作成できたため、完了レポートからテストファーストとテスト後を区別できませんでした。これらを導入した後は、マトリックスで GREEN 前の RED 出力そのものが必須になります。そのため、RED を省略した実行には提示できる出力がなく、マトリックスは構造上不完全になります。