10.3 良いテストを書く
内容
テスト駆動開発として実践されている「テストファースト開発」と「テストアフター開発」を紹介し、多くの開発者やマネージャーは「テストアフター開発」によって、テスト駆動開発に対するネガティブな誤解を生んでいることを説明している。
- テストファースト開発
- 説明
- 小さな機能のテストを書いてから、その機能を実装するやり方。
- メリット
- テストの観点(外部からの観察)と、コードの観点(内部からの観察)を行き来することで、フィードバックをもらいながら堅実に進められる。
- 最初にテストを書くことで、常に100%のコードカバレッジが確保できる。
- 失敗したテストに合格するようにコードを書くため、テスト可能なコードが書けていることを保証してくれる。
- デメリット
- テストを書くスキルの習得が要る
- 説明
- テストアフター開発
- 説明
- コードを書いてからテストを書く。(著者がそう呼んでいる)
- メリット
- 自動化された回帰テストを好きなときに作って実行できる。
- デメリット
- コードを書いたあとにテストを書くのは、かなりの再設計、コードをクリーンアップが必要であることがほとんど。結局、テスト可能なコードを最初に作成するほうが楽。
- 説明
この実態を前提に、多くのマネージャーと開発者は、テスト駆動開発に対し、テストアフター開発のイメージを持ち「やたら手がかかる」というような先入観を持っている。
テストファースト開発では、テストアフター開発のデメリットを防ぐことができる。
すべてのテストを先に書いてから、実装する方法もある。この方法にはいくつかの利点があるのは事実だが、テストファースト開発で得られる頻繁なフィードバックのほうが大きな利点である。
著者はすべてのテストを先に書いてから実装する方法はテスト駆動開発とは考えていない。
10.3.1 テストではない
テストは二重の役割を果たしているということを説明している。
- 1つは、仮説であり、ふるまいの仕様。
- もう1つは、回帰テストが常に用意されていて実行され、コードが期待したように機能していることを検証すること
コードを書く前に書いているユニットテストはテストではなく仮説。
サービスの呼び出し方法と期待する戻り値の仮説を立てている。
つまり、どうなったら完成するのかの仮説を立てている。
次に、テストに合格するコードを書いたら実際のテストになる。
なんらかのふるまいを実行して検証したから。
そしてこの検証機能はソフトウェアの寿命が来るまで以下の価値を提供し続ける。
- 影響を与える可能性のあるものは何も変わっていないことを保証する
- コードが期待したように動くことを保証する
10.3.2 ふるまいの集合体
ユニットとはふるまいの単位で独立した検証可能なふるまいのこと。
つまり、どのように使ってどのような結果になるかを検証できるふるまいのこと。
ふるまいを表すために、常に必要最小限のテストを書くことが重要。
多くの開発者は「ユニットテスト」の「ユニット」と言う言葉を、メソッド、クラス、モジュール、関数などのような実体を指すものと勘違いするが、違う。
この勘違いのため、新しいクラスやメソッドを作るたびに新しいテストを作成し、コードの成長とともに多くのテストを追加することで、肥大化するのではないかと心配したり、実際に追加してしまう。
テストファーストのメリットは、必要に応じてあとから簡単にコードをクリーンアップできるようにすることだ。
ユニットの単位を勘違いして、コードをクリーンアップするときに、不要なテストを増やしてしまうと、自動回帰テストを持つことの価値の大部分を失ってしまう。
「ユニット」が表現するのはふるまいだ。
ふるまいが変わらないなら、テストを変える必要はない。
「ユニットテスト」は「すべてのクラスやメソッドがテストを持つべき」ではなく「あらゆる観察可能なふるまいが、それに紐づくテストを持つべき」である。
「あらゆる観察可能なふるまい」=「すべてのクラスやメソッド」というわけではない。
学び
実際にテストアフター開発が起きているからネガティブな先入観が生まれる。
では、なぜテストアフター開発をしてしまうのか。要因は、大きく2つ。
- 傲慢。
ほとんどの開発者はテスト可能でないコードを書いてしまう前提を認識していない。 - 無知。
テストファースト開発が習得が必要なスキルだということを知らない。
間違った認識、無知は失敗を生み、ネガティブな先入観を生む。
- テストファーストで書くテストは、実際のコードまで書いて、テストとなる。テストだけの時点では、ふるまいの仕様を表す仮説である。
- 自動回帰テストの環境がないと効果が薄いように感じる。
- ユニットとは観察可能なふるまいの単位である。
- ユニットの単位を明確にして不要なテストを増やしてはいけない。
学びを活かすアイディア・行動
- テストコードの目的のための事前知識準備
- 現場の回帰テスト環境作り
- ユニットの単位の深堀り
- 現場のテストコードのコーディング規約づくり