Drives implementation work through the Red-Green-Refactor TDD cycle (TODO list decomposition, fake it / obvious implementation / triangulation, and test structure refactoring), based on Takuto Wada's TDD Boot Camp talk. Use when the user asks to implement a feature or fix "using TDD" / "TDDで" / "テスト駆動で", or asks to develop test-first.
Resources
1Install
npx skillscat add neko3cs/skills/test-as-tdd Install via the SkillsCat registry.
test-as-tdd Skill
概要
このスキルは、実装作業を TDD(テスト駆動開発) のサイクルで進めることを強制します。和田卓人氏の TDD Boot Camp 2020 ライブコーディング(参考資料)で示された手順に基づき、以下を実施します。
- 仕様をTODOリストに分解する
- Red → Green → Refactor のサイクルを1項目ずつ回す
- テストを日本語の自然文で命名し、テストコード自体が仕様書として読めるように構造化する
TDDは品質保証の手段ではなく、コードを綺麗に保ちながら安心して開発を進めるための設計手法です。歩幅を小さく保つことで手戻りを防ぎます。
実行手順
1. TODOリストを作る
実装を始める前に、要求された仕様を「これが通れば仕様を満たす」と言えるレベルまで小さなテストケースの単位に分解し、リスト化してください。
- 例(FizzBuzz): 「1を渡すと"1"を返す」「2を渡すと"2"を返す」「3の倍数で"Fizz"を返す」「5の倍数で"Buzz"を返す」「15の倍数で"FizzBuzz"を返す」
- 順番は「最も簡単で、次のテストへの足がかりになるもの」から着手します。
- 作業中に新しい疑問・ケースに気づいたら、その場でTODOリストに追加してください。
2. 1項目ずつ Red → Green → Refactor を回す
TODOリストから1項目だけを選び、以下を順に実施します。複数の項目を同時に進めないでください。
Red(失敗するテストを書く)
- まだ存在しないクラス・メソッドに対して、「理想の使われ方(インターフェース)」をイメージしながらテストを先に書きます。
- テストを実行し、意図した理由で失敗することを確認してください。コンパイルエラー(ビルド失敗)も正当なREDです。
- 失敗理由が想定と違う場合(例: 別の理由でエラーになっている、誤って常にパスしてしまうなど)は、ザルなテストになっていないかを必ず確認してから次に進んでください。
Green(最速でテストを通す)
テストを通すための実装は、状況に応じて次の3つの戦略から選んでください。
- 仮実装(Fake It): 期待値をハードコードして即座にGreenにする(例:
return "1";)。正しさや美しさは後回しにし、まずテストが通る安心感を最速で得ます。 - 明白な実装(Obvious Implementation): 実装ロジックが自明で確信がある場合は、最初から正しいコードを直接書きます。
- 三角測量(Triangulation): 一般化の方向に確信が持てない場合、もう一つテストケース(TODOリストの次の項目)を追加し、2つの具体例から一般化を強制的に導きます。
どの戦略でも、Greenになるまでは他のことを考えず、最短距離で通すことを優先してください。
Refactor(テストを保ったまま綺麗にする)
- Greenの状態を維持しながら、重複の除去・一般化・命名の改善を行います。
- 小さな変更ごとにテストを再実行し、常にGreenであることを確認してください。Greenが崩れたら直前の変更を見直します。
- リファクタリングは「製品コード」だけでなく、必要であれば直前に書いたテストコードにも適用します。
このサイクルが完了したら、TODOリストの該当項目をチェックし、次の項目に進みます。リストが空になるまで繰り返してください。
3. テストを日本語で命名し、仕様書として成立させる
テストコードは「動く仕様書」として読める状態を目指します。Red を書く最初の時点から、この命名規則を適用してください(肥大化してから直すのではなく、最初から仕様書として書きます)。
命名規則
- テストクラス名:
{テスト対象名}Test(例:FizzBuzz→FizzBuzzTest)。 - セットアップメソッド:
setUp/@BeforeEach相当のメソッドも日本語名にする(例:前準備)。 - 仕様の文脈(グルーピング): 関連するテストケースを、言語・フレームワークのグルーピング機構でまとめ、そのグループ名を仕様を表す自然文にする。
- Java:
@Nested class 数を文字列に変換する { ... } - TypeScript (Jest/Vitest):
describe("数を文字列に変換する", () => { ... }) - Ruby (RSpec):
context "数を文字列に変換する" do ... end - C# (xUnit): 入れ子クラス
public class 数を文字列に変換する { ... } - Swift (XCTest): メソッド名で文脈を表現するか、
XCTestCaseを仕様ごとに分割する
- Java:
- テストケース名: 「入力に対してどう振る舞うべきか」を期待結果まで含めた自然文にする(例:
_1を渡すと文字列1を返す、_3を渡すと文字列Fizzを返す)。- テスト名を**識別子(メソッド名)**として書く言語(Java, C#, Swiftなど)では、数字から始まる名前は不正なので先頭に
_を付ける(例:_1を渡すと...)。 - テスト名を**文字列(description)**として書くフレームワーク(Jest/Vitestの
it、RSpecのitなど)では、_を付けずそのまま自然文の日本語文字列を使う(例:it("1を渡すと文字列1を返す", () => {...}))。
- テスト名を**識別子(メソッド名)**として書く言語(Java, C#, Swiftなど)では、数字から始まる名前は不正なので先頭に
構造化の例(Java / JUnit5, FizzBuzz)
class FizzBuzzTest {
private FizzBuzz fizzbuzz;
@BeforeEach
void 前準備() {
fizzbuzz = new FizzBuzz();
}
@Nested
class 数を文字列に変換する {
@Test
void _1を渡すと文字列1を返す() {
assertEquals("1", fizzbuzz.convert(1));
}
}
@Nested
class _3の倍数のときは数の代わりにFizzに変換する {
@Test
void _3を渡すと文字列Fizzを返す() {
assertEquals("Fizz", fizzbuzz.convert(3));
}
}
}このテストクラスをそのまま実行結果(JUnitのテストツリー)として見ると、「数を文字列に変換する」「3の倍数のときは数の代わりにFizzに変換する」という仕様が、実装を読まなくても伝わる構成になります。
補足
- テストが肥大化してきた場合も、上記の命名規則に沿って既存のテストをグルーピング・リネームし直してください。テストコードは製品コードと同じ、あるいはそれ以上の丁寧さでメンテナンスします。
- 英語でテストを書く既存プロジェクトに途中から適用する場合は、新規追加分から日本語命名に揃え、必要に応じて既存テストも段階的にリネームしてください。
他のスキルとの関係
test-as-tdd は**実装の進め方(設計サイクル)**を定義するスキルです。プロジェクト全体の品質ゲート(フォーマット・カバレッジ・ミューテーションテストなど)は別スキルが担当します。TDDサイクルを終えたら、test-project で最終確認を行ってください。resolve-issue スキルからIssue対応の一部として呼び出される場合は、ステップ4「Issueを解決する」の実装フェーズでこのスキルのサイクルを適用してください。
サンプル対話
User: FizzBuzzをTDDで実装してください。
Agent: まずTODOリストを作成します。「1→"1"」「2→"2"」「3の倍数→"Fizz"」「5の倍数→"Buzz"」「15の倍数→"FizzBuzz"」に分解しました。最初の項目からRed-Green-Refactorを回します。
User: いきなり正しい実装を書いてもいいですか?
Agent: 確信があるロジックであれば「明白な実装」として直接書いて構いません。ただし確信が持てない場合は、まず仮実装でGreenにしてから一般化する方が安全です。
User: テストが増えてきて読みにくくなりました。
Agent: テストを仕様の文脈ごとにグルーピングし、ケース名を自然言語で書き直して構造化しましょう。
User: テストメソッド名はどう書けばいいですか?
Agent: {対象}Test というクラス名の中に、仕様を表す自然文のグループ(@NestedやJestのdescribeなど)を作り、その中に期待される振る舞いを自然文で表したテストケース名(例: _1を渡すと文字列1を返す)を置きます。識別子として書く言語では数字始まりの名前に _ を付けてください。