test-writing について
開発者やコーディングエージェント向けに、信頼性が高く低コストな検証範囲の選び方を示すテストスキルです。振る舞いに基づくテスト、再現可能な環境、原因の明確な失敗、プロジェクト必須チェックの完了を重視します。
主な機能
- 01複雑さの所在に応じたテスト範囲の選択
- 02再現可能で低コストなテスト環境の優先
- 03実装構造ではなく振る舞いの検証
- 04可能な場合の実ローカル依存関係の利用
- 05原因を特定しやすい失敗の維持
活用シーン
- 01ドメインロジック変更に適したテストの選択
- 02データベースやファイルシステム動作のローカル検証
- 03サービス境界に沿った統合テストの計画
- 04壊れやすい、または誤解を招くアサーションの確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ wilbeibi/ wilbeibi-skills --skill test-writingインストール後、Claude Code で/test-writingを入力して読み込まれたか確認します。
同梱ファイルREFERENCE.md
詳細
test-writing
隔離性を保ち、低コストでセットアップできる範囲で、できるだけ広い境界を通して動作をテストします。
変更内容に見合った検証を選び、プロジェクトで必須のチェックをすべて実施します。 好みのテストスタイルに従うためだけに、本番コードの範囲を広げないでください。
改めるべき習慣
- 書いたばかりのコードをもとにテストを書く。 実装を読んで、その動作をアサートすると、バグまでテストに織り込んでしまいます。期待値は要件から導き、手計算してください。コードを実行せずに期待する答えを示せないなら、テストに必要なほど動作を理解できていません。
- 実際の出力を期待値にコピーする。 テストを実行して失敗するのを確認し、実際の値を貼り付けても、それは記録であってテストではありません。許容範囲を広げて通るようにするのも同じです。
- コード構造をそのまま写す。 ソースファイルごとにテストファイルを1つ、公開メソッドごとにテストを1つ作るのは、コードの単位に基づくテストスイートです。動作の単位をテストしてください。1つの動作を何個のクラスで実装しているかは関係ありません。
- デフォルトでモックを使う。 低コストかつ決定的に実行できるなら、実際のローカル依存関係を優先してください。信頼できる結果が得られる場合は、外部との境界にフェイクやモックを使います。それがあるというだけで、設計変更が正当化されるわけではありません。
- コードではなくテストを修正する。 失敗したテストは、反証されるまではコードについての仮説です。グリーンにするためにアサーションを弱めたり、モックを追加したり、テストをスキップしたりしてはいけません。1つのコミットでテストとその対象コードを変更するなら、両方が誤っていた理由を明示する必要があります。
- グリーンにするために環境を変更する。 手作業で行を追加する、フラグを切り替える、サービスを再起動する、キューを空にするといった操作は、デプロイ環境でアサーションを弱めるのと同じです。テストは通りますが、何も修正されず、共有状態がほかの人にとって変わってしまいます。
- 共有環境で試行錯誤しながらデバッグする。 そこでの失敗は、あなたの変更、ほかの人の変更、古いデータ、環境の故障のいずれが原因か、最初から判別できません。まず隔離されたテストでローカルに再現してください。できない場合は推測せず、その旨を伝えてください。
- スナップショットを無条件で受け入れる。 差分を読まずに更新モードを実行すると、expect-testの反復が自動承認の反復になってしまいます。レビューしていないスナップショットの更新は、未テストの変更として扱ってください。
- 量を増やす。 低コストなテストがほぼ同じ内容のものばかりになると、まとめて失敗し、本当の失敗を埋もれさせます。カバレッジ率もテスト数も目標ではありません。
- 失敗を隠す。 壊れた動作をグリーンにしてしまうリトライや例外処理は避けてください。失敗が明確に分かるなら、非同期動作に上限付きの待機やタイムアウトを設けるのは適切です。
- フレームワークをテストする。 ORMが保存することや、標準ライブラリがソートすることをアサートするのは、ほかの人のコードをテストしているだけです。
エージェント主体の反復では、テストスイートは安全網ではなく、最適化の対象となる受け入れ基準です。同語反復のようなテストスイートは、単にバグを見逃すだけでなく、作業を誤った方向へ導きます。
ルーティング
まず、複雑さが実際にどこにあるのかを確認してください。テストスイート全体の形が決まるためです。
- プロセス内部 — アルゴリズム、ドメインルール、パーサー。ドメイン層を深くテストし、境界テストでは配線を確認するだけにします。
- 境界部分 — サービス、接着部分、オーケストレーション。契約そのものが成果物なので、現実的なフィクスチャを使ってエッジからテストし、実装詳細のテストは、本当に複雑で独立した要素に限ります。
次に、以下の手順に従います。
- 単純な接着部分やゲッターですか?スキップします。失敗しようのないテストは、失敗のシグナルにノイズを加えるだけです。
- 純粋なロジックで、依存関係が少ないですか?公開 API を通じてテストします。個別に選んだ例より、プロパティテストや網羅的なテストを優先します。
- オーケストレーション、実際の I/O、コントローラー/データベース/ファイルシステムの動作ですか?統合テストを行います。モジュールまたはサービスを単独で実行し、その依存関係には実物を使い、協調する要素はエッジでフェイクにします。
- 複雑で、かつ依存関係が多いですか?ドメインロジックを切り出してテストし、薄いオーケストレーターは統合テストに残します。
- デプロイ、配線、実際のサードパーティの動作、または負荷がかかったインフラですか?デプロイ済み環境が必要なのはその部分だけです。共有ステージングより、一時的な環境(PR ごとのスタック、Compose ファイルなど)を優先します。
セットアップが高コストになるか、テストがハーメチックでなくなるまで境界を広げ、そこで止めます。基準は I/O ではありません。ループバック HTTP やプロセス内の SQLite は低コストですが、共有リモートデータベースはそうではありません。コストになるのは、セットアップ時間、リソース使用量、そして制御できないものです。
ルール
- 日常的なテストは共有外部サービスから独立させます。実際の外部契約の検証自体が目的の場合は、対象を明示した統合テストまたはエンドツーエンドテストを使い、環境に起因する失敗は別途報告します。
- 失敗したときに不具合の箇所を特定できるようにします。「システムのどこかに問題がある」としか示さない失敗結果は、次の手が推測になるため、テストを繰り返すサイクルではほとんど役に立ちません。
- 1 つのテストにつき、ドメインの専門家が認識できるシナリオを 1 つにします。メソッドではなく、動作に基づいた名前を付けます。
- まず出力ベースのテストを優先し、次に状態ベースのテストを使います。通信モックは、互換性に影響する外部呼び出しに限って使用します。
- 管理対象外の依存関係にはフェイクを使い、実用上可能な場合はローカルのデータベースやファイルシステムを実際に使います。テスト対象の動作に合わせて境界を定めます。
- 時間に依存する動作には、注入したクロックか、プロジェクトで確立されたフェイクタイマーの仕組みを優先します。非同期処理は完了を待つか、制限時間のある公開シグナルを通じて完了を確認します。
- Arrange、Act、Assert の順にします。Act は 1 つの操作にします。失敗原因を 1 つに絞れるよう、アサーションの範囲を限定します。
- セットアップは必要とするテストの範囲内に保ちます。クラスレベルで共有するフィクスチャは、デバッグの対象となる個々のテスト実行すべてに負担をかけます。
- キャッシュヒットやフォールバックの使用といった動作には、既存の公開された可観測性を優先して利用します。実装上の分岐をアサートするだけの目的ではなく、要求された契約に必要な場合にのみ計測機能を追加します。
警告サイン
- 期待値の根拠が要件ではなく、実際の出力にある。
- テストが答えをハードコードせず、本番ロジックを複製している。
- 内部実装、プライベートメソッド、呼び出し順、クラスの構成を確認しているため、リファクタリングでテストが壊れる。
- 複数のサービスの起動や、共有環境の正常稼働がテストの成功条件になっている。
- データベースやファイルシステムの動作をモックで置き換えている。
- 終了条件のないスリープやリトライ、または失敗を抑制する条件分岐がある。
- 説明がないまま、テスト対象のコードと同じコミットでテストも変更されている。
品質基準
テストは、信頼できる検証シグナルかどうかで評価します。動作が壊れたときに失敗し、リファクタリング後も成功し、失敗時には明白な原因を 1 つ示す必要があります。リファクタリングへの耐性が最も重要です。それがあって初めて、テストスイートが成功していることに意味が生まれます。誤った形を固定するテストは、信じられてしまうため、テストがないより悪い結果になります。
テストの規模、ピラミッドとハニカムの選択、check() の継ぎ目、可観測性のポイント、expect テスト、プロパティテストとファジングテスト、Humble Object リファクタリング、データベースのパターンについては、REFERENCE.md を参照してください。