TDD が効かない場面: 適用条件とまとめ
ここまで 13 章かけて、テストを先に書く進め方を見てきました。最後に、この進め方が割に合わない場面を扱います。
「TDDテスト駆動開発 (TDD)実装より先にテストを書き、そのテストを通す形で実装を進める書き方。テストを書く時点が実装より前にあることが要件で、カバレッジを上げる活動とは別。 が向かない領域」という言い方は、あまり役に立ちません。領域ではなく条件で決まるからです。同じ Web アプリケーションでも、ある部分では効いて、別の部分では効きません。
この章では、コストが何に比例するかを先に整理し、そこから条件を導きます。
この章で学ぶこと
- テスト先行のコストが何に比例するか
- 割に合わなくなる 4 つの条件
- 全面適用と不採用の間にある選択肢
第 1 部を読んでいることを前提にします。
この章で扱わないこと
本ガイド全体が扱わなかったものを、ここでまとめます。
| 観点 | 扱い |
|---|---|
| ブラウザを動かす E2E テスト、ビジュアルリグレッション | 範囲外です |
| 負荷試験、パフォーマンスの計測 | 範囲外です |
| 継続的インテグレーションでのテスト実行 | AWS 実践ガイド |
| テストフレームワークの設定と導入 | TypeScript 開発ツールチェーン と Pest でテストを書く |
| どの層にどれだけテストを書くかの配分 | テスト戦略 |
コストは何に比例するか
テストを先に書くコストは、次の 3 つに比例します。
**書き直す回数。**先に書いたテストは、仕様が変わると書き直します。仕様が動いている間は、実装とテストの両方を書き直すので、往復が 2 倍になります。
期待値を決める手間。「こうなってほしい」を言葉にできないと、テストが書けません。数値や文字列なら書けますが、見た目や文章の良し悪しは書けません。
**対象を単独で動かす手間。**テストから対象を呼べる状態にするのが高くつくことがあります。03 章と 12 章で扱ったのはこの話です。
回収するのは、あとで何度も走らせることによってです。1 回しか走らせないなら、書くコストがそのまま損失になります。
4 つの条件
上の比例関係から、割に合わなくなる条件が出てきます。
仕様が動いている
新機能の形をまだ決めていない試作、利用者に見せて反応で方向を決める画面、要件が固まる前に仮で作る入力欄。何を作るかを探している段階では、実装もテストも捨てる前提になります。書き直す回数が予測できません。
この段階では、動くものを早く作って見せる方が情報が得られます。方向が定まってから、残すと決めた部分にテストを入れます。
ただし「探索中だから」を理由に、いつまでもテストを書かない状態が続くことがあります。探索が終わった時点を決めておくと、そこが切り替えの目印になります。
出力を機械で判定できない
画面の見た目、文章の読みやすさ、操作した感触。これらは「正しい」を言葉にできません。期待値を決める手間が、原理的に払えないということです。
ただし、これは「テストを書けない」とは違います。見た目は判定できなくても、操作したときに何が起きるかは判定できます。09 章と 10 章で書いたのはそちらです。
分けて考えます。判定できるものはテストにし、判定できないものは人が見ます。判定できない部分があることを理由に、判定できる部分まで手放さないのが要点です。
環境を用意する手間が本体を上回る
外部サービスとの連携、特定のハードウェア、複雑なインフラ構成。対象を単独で動かすために必要な準備が、対象そのものより大きいことがあります。
この場合、境界の外側に出すのが先です。07 章でやったように、外部との境目をインターフェースにして、そこから内側だけをテストします。外側は数を絞って、実環境で確かめます。
それでも準備が支配的なら、テスト先行の前に設計を見直す方が早いこともあります。
コードの寿命が短い
1 回だけ実行する移行スクリプト、検証のための使い捨てコード。走らせる回数が少ないので、回収できません。
ただし「使い捨てのつもりだったものが残る」のはよくあります。残ると決まった時点でテストを入れるか、最初から短く保って読めば分かる状態にしておくかの選択になります。
全面か不採用かではない
4 つの条件に当てはまっても、テスト先行を完全にやめる必要はありません。間に選択肢があります。
| 形 | 内容 |
|---|---|
| 部分適用 | 判断が集まる部分だけテスト先行にし、変換や配線は後から書く |
| 後追いで固定 | まず動くものを作り、残すと決めた時点でテストを入れる |
| 特性テスト特性テスト (Characterization Test)既存コードのいまの振る舞いを、正しさを問わずそのまま固定するテスト。変更の前後で振る舞いが変わっていないことを確かめる手段になる。から入る | 既にあるものに後から入れる。12 章の手順 |
| 境界だけ守る | 外部とのやり取りだけテストで固定し、内側は自由にする |
現実のプロジェクトでは、これらが混ざります。ドメインの中心は先に書き、画面の細部は後から固定し、レガシーな部分は触るときだけ特性テストを入れる。1 つの方針を全体に当てないことが、実務での使い方です。
まとめ
本ガイド全体で扱ったことを、3 つに畳みます。
**順序が内容を変える。**同じ機能でも、実装の前に書いたテストと後に書いたテストは中身が違います。前者は仕様を問い、後者は実装を追認します (01 章)。
**書きにくさが情報になります。**テストが書きにくいとき、それは対象が外から使いにくいということです。テスト側で歪めるか、設計を直すかの分かれ道が、実装を決める前に来ます (03 章、07 章、11 章)。
**当て先が寿命を決める。**何に結びつけてテストを書いたかで、いつ落ちるかが決まります。利用者に見えるものに当てれば、リファクタでは落ちません (05 章、09 章)。
この 3 つは、言語やフレームワークに依りません。本ガイドが PHP と React の両方を題材にしたのは、それを見てもらうためです。
次に読む
- はじめに — 全体の構成に戻る場合
- テスト戦略 — どの層にどれだけ書くかという、本ガイドとは別の問い
- Laravel × DDD × クリーンアーキテクチャ実践ガイド — 13 章で送った先。ドメインモデルの設計そのもの