mcpField
T
testing-on-the-toilet

testing-on-the-toilet

github.com/shamashelテスト・品質3656 回インストール9 週間前に更新
リポジトリ

testing-on-the-toilet について

Google Testing on the Toilet のテスト原則をまとめた、テスト作成・レビュー向けのガイドです。観測可能な振る舞いの検証、適切なテスト層やテストダブルの選択、実際の不具合を検出できるかの確認を扱います。

主な機能

  1. 01実装をなぞるテストの識別
  2. 02リスクに応じたテスト層の選択
  3. 03実オブジェクトやテストダブルの選択
  4. 04明確で焦点を絞ったアサーション
  5. 05分離された決定的なテスト
  6. 06不具合を検出できるかの確認

活用シーン

  1. 01テストが振る舞いを検証するかレビュー
  2. 02新機能に適したテスト層を選択
  3. 03壊れやすいモック中心のテストを削減
  4. 04テストの決定性と有効性を確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/shamashel/testing-on-the-toilet --skill testing-on-the-toilet

インストール後、Claude Code で/testing-on-the-toiletを入力して読み込まれたか確認します。

同梱ファイルreferences/episodes.md

詳細

Testing on the Toilet

Google の「Testing on the Toilet」のエピソード(2007–2026)から要点をまとめたものです。エピソードの一覧:references/episodes.md。

新しいテストを作成するときも、テストをレビューするときも、このサイクルを実行してください。完了条件:リリースされる各テストが、実際の動作上のバグで失敗し、動作を維持するリファクタリングでは通過すること。

1. 変更検知ゲート

変更検知テストとは、観測可能な結果を検証せずに、本番コードの構造(特に、すべての協力オブジェクト呼び出しに対する順序付きのverify)を再現するテストです。正しい実装も誤った実装も同じように通過し、名前の変更、抽出、順序の変更をするとテストスイートが失敗します。

状態、戻り値、描画結果、または永続化されたデータを検証するテストに書き換えてください。ユーザーから見える契約を特定できない場合は、テストを削除し、その理由を説明してください。50個のミラーを機械的に更新してリファクタリングを「修正」してはいけません。

呼び出しそのものが契約である場合(メールを一度送る、二重請求しない、プレゼンターがビューにXの表示を指示する)に限り、インタラクションのverifyが許容されます。判断に迷ったら、状態または戻り値を検証するテストに書き換えてください。それが不可能な場合は、作業を止め、そのテストがどの観測可能な結果を保護するのか確認してください。

2. 十分な忠実度を保てる最も低コストのレイヤーを選ぶ

まずバグやリスクを明確にします。そのリスクを検出できる表の最上位の行を選びます。より低コストのレイヤーではそのリスクを見逃す場合に限り、レイヤーを上げてください(見逃す理由を明記します)。2つの行でどちらも検出できる場合は、トレードオフを表す言葉としてSMURF(Speed、Maintainability、Utilization/cost、Reliability、Fidelity)を使い、より低コストで高速かつ信頼性の高い方を優先します。

リスクレイヤー
純粋なロジック、解析、検証、リデューサー公開 API経由の高速な単体テスト
自分が所有するプロセス内の協力オブジェクト実オブジェクト、または所有者が保守するフェイク
サービス/HTTP 契約所有者のフェイクまたは隔離されたサーバー。手書きのリクエストモックは使いません
UI の配線(無効、未バインド、非表示)ハンドラーではなく、描画されたコントロールを操作する(クリック/入力)
システムをまたぐ重要な経路最小限の E2E セット:ユースケースごとに1つの経路と、主要なエラー分類。文言やレイアウトではなく、システムの結果を検証する

レイヤーを積み重ねる前に、主なリスクを洗い出してください。カバレッジの指標はギャップを見つけるものであり、品質を保証するものではありません。分岐の両側をカバーしてください(暗黙のelseも対象です)。組み合わせを網羅的に列挙するのは避け、述語を抽出してそれぞれを個別にカバーしてください。

公開 API経由のテストを優先してください。呼び出し元が渡さない入力に対するプライベートヘルパーの網羅的なテストは、見せかけの変更検知テストです。

3. テストダブルを選ぶ

順序は実オブジェクト → フェイク → スタブ → モックです。モックは最後に使います。

  • 高速で、決定論的で、プロセス内で動作するなら、実オブジェクトを使います。
  • フェイク:自分(またはライブラリの所有者)が保守する、型の簡略化された実装です。対象を絞ってください。フェイクを共有する場合は、フェイクと実オブジェクトをコントラクトテストで比較してください。
  • スタブ:問い合わせに対して、あらかじめ定めた値を返します。ゲッターをverifyしてはいけません。
  • モック:インタラクション自体が仕様である副作用を伴う呼び出しを検証します。

厳守事項:

  • 自分が所有していない型をモックしないでください。サードパーティ API をラップし、そのラッパーをモックして、ラッパーを実際のライブラリに対してテストしてください。
  • 2つ以上の協力オブジェクトをモックする場合や、長いwhen/verifyチェーンがある場合は、接合部の臭いです。より狭いポートを抽出して、それをフェイクにしてください。
  • 長期間使う協力オブジェクトはコンストラクターで注入し、呼び出しごとの処理はメソッドの引数として渡してください。隠れたシングルトン、モックできない静的メソッド、テスト対象のロジック内のnow()は避けてください。

4. テストを作成する(DAMP)

テストでは、DRY よりも DAMP(説明的で意味のあるフレーズ)が優れています。テストにはテストがありません。読者がメソッド本体で原因と結果を隣り合わせに確認できる必要があります。

  • 1つのテストにつき1つの振る舞い。 unit_scenario_expectedOutcome(またはプロジェクトで同等の形式)という名前を付けます。testFoo は名前とは言えません。
  • 1つのブロック内で 準備・実行・検証 を行います。アサーションから遠く離れた @Before の寄せ集めは、誤った期待値が紛れ込む原因になります。
  • ヘルパーで隠すのは 無関係な 構築処理です。シナリオに関係するフィールドはテスト内で 見える状態 にします。デフォルト値を備えたビルダーやファクトリーは適切ですが、ヘルパーのデフォルト値を暗黙に検証するのは適切ではありません。
  • 入力と期待される出力には リテラル を使います。期待値の計算に、本番コードと同じバグを含む可能性のあるループや条件分岐を使わないでください。ヘルパーにロジックを含める必要がある場合は、そのヘルパーをユニットテストします。
  • 対象を絞ったアサーション:オブジェクト全体、スクリーンショット、ハッシュの順序ではなく、テスト対象のフィールドを検証します。一般的な正常系オブジェクトには、全体の等価性チェックを1つ行えば十分です。
  • 入力ごとに 異なるデフォルト以外の値 を使います(0、""、最初の列挙値は未初期化状態と一致し、誤ってテストを通過させる可能性があります)。
  • 原因の特定に役立つ失敗:assertTrue(result.ok()) よりも、具体的なマッチャー(containsEntry、エラーテキスト付きの isOk)を使います。独立したチェックは後続も実行されるようにします(EXPECT)。後続のアサーションに意味がない場合は除きます(ファイルを開く処理では ASSERT)。
  • 浮動小数点数:厳密な等価性ではなく、許容誤差 を使います。
  • UI ロケーター:コピーや壊れやすい XPath ではなく、安定したテスト ID を使います。

5. 隔離性と決定性を保つ

実際の時計を使わず、同期に sleep を使わず、ユニットテストで実ネットワークやディスクを使わず、共有ファイルや共有行が空であることを前提にしません。

  • クロックを注入し、進めます。
  • タイムアウト付きでラッチやイベントを待つか、フェイクスケジューラーを進めます。
  • テストごとに一意な一時パスや分離されたフィクスチャを使います。
  • タイムアウトやスローされたエラーなどのまれな失敗は、テストダブルを通して強制します。実際のインフラではできません。

6. テストが失敗することを証明する

ローカルで作成または編集するときは、まずテストを成功させ、その後、本番コードを壊す(またはアサーションを反転する)ことで、失敗する ことを確認します。レビュー時に実行できない場合は、このアサーションで検出できる具体的な振る舞いのバグを1つ記述します。それができない場合は、変更検知にすぎないものとして扱い、承認しないでください。

テストをリファクタリングするとき は、まず本番コードを既知の不具合がある状態にして、削除されたアサーションが検出されることを確認してから、本番コードを元に戻します。この確認をせずに、テストを成功状態から成功状態へ「整理」してはいけません。

残っているテストが恒真命題、実装を模倣したモックスクリプト、またはロジックのない配線だけである場合は、追加しないでください。リスクを担うべき接続点やレイヤーが不足していることを報告してください。

プロジェクトの慣習がここでの絶対ルール(すべての協調オブジェクトのモックを必須とする、sleep に基づく待機、プライベートヘルパーのみをテストするなど)と矛盾する場合は、中止して矛盾を指摘してください。より緩い慣習に黙って従ってはいけません。

レビューチェックリスト

マージするテスト:

  • 名前変更や抽出だけでなく、実際の振る舞いのバグで失敗する
  • 呼び出しの台本ではなく、結果や状態をアサートする(呼び出し自体が契約である場合を除く)
  • 到達不能なヘルパーではなく、公開 API またはユーザー向けの経路をテストする
  • 原因と結果が見え、名前に結果が示されている
  • 決定的である(クロック、I/O、一意性に対処している)
  • 追加のログなしで修正に着手できる失敗メッセージが表示される

コメント