thasmto's blog

フロントエンドエンジニアやってます。プログラマーとして学んだことや考えていることを投稿するブログです。

テスト駆動開発 第一部

テスト駆動開発の第一部を読んだのでそのメモ。

TDDのゴール

「動作するきれいなコード」

(以下、本書の引用)

「動作するきれいなコード」。RonJeffriesのこの簡潔な言葉が、テスト駆動開発(TDD)のゴールだ。動作するきれいなコードはあらゆる意味で価値がある。

開発が予測可能になる。 完成したかどうかがわかり、バグが残っているかを心配する必要もない。 コードが伝えようとしていることを余すところなく受け取れる。 最初に思いついたコードを書き殴っただけで終わりなら、再考してより良いコードを書くチャンスは永遠に来ない。 あなたが作るソフトウェアのユーザを快適にする。 チームメイトはあなたを信頼し、あなたもまたチームメイトを信頼する。 書いていて気持ちがいい。

TDDのルール

  • 自動化されたテストが失敗したときのみ、新しいコードを書く。
  • 重複を除去する。

TDDの流れ

  1. まずはテストを1つ書く
  2. すべてのテストを走らせ、新しいテストの失敗を確認する
  3. 小さな変更を行うすべてのテストを走らせ、すべて成功することを確認する
  4. リファクタリングを行って重複を除去する

まずはテストを1つ書く

TDDはテストを書くところから始まる。 テストを書くときに用途にあったインターフェースを考える。そのコンポーネントや関数がどのように呼び出されるのか、どのようなプロパティを受け取りどのような値を返すのか理想的なAPIから考える。

すべてのテストを走らせ、新しいテストの失敗を確認する

テストの内容をプロダクトコードに反映していないので、テストは当然失敗する。

小さな変更を行うすべてのテストを走らせ、すべて成功することを確認する

コードのクオリティは気にせずテストを通すための実装をする。 すばやくテストを通すために以下の2つの書き方を意識する。 仮実装:コードでまずベタ書きの値を使い、実装を進めるに従って、徐々に変数に置き換えていく。 明白な実装:すぐに頭の中の実装をコードに落とす。

リファクタリングを行って重複を除去する

べた書きで値を返してしまっている箇所や重複したコードなどリファクタリングしていく。 すでに自動テストがあるので、安心してコードを修正できる。

はじめは小さいステップで

この流れを小さいステップで繰り返していく。大きな処理は最初から正しいアーキテクチャで書くことは難しく、書き終わったあとに根本から修正することが難しくなる。

ただし、ステップは可能な限り小さくしなくてもいい。これまでの実装から正しい実装を書けると判断できる場合には小さいステップは省いてしまってもいいし、正しい設計が思いつかないのであればまずは小さいステップからはじめてもいい。

(以下、本書の引用)

TDDを行う際には、常にこのような微調整を行う。非常に細かなステップを窮屈に感じるならば、歩幅を大きくする。不安を感じるならば、歩幅を小さくする。TDDとは、あちらへ少し、こちらへ少しといった感じで舵を取るプロセスだ。正しい歩幅などというものは、未来永劫に存在しない。

そのほかTDD中に考えること

多少の回り道もOK

かならずしもTDDの流れに従わなくてもいい。 必要に応じて実装を先に書いたり、言語仕様を確認するためのテストを書いたりしてもいい。

(以下、本書の引用)

この修正をいま行うべきだろうか。それとも待つべきだろうか。教科書的な答えは「いま行っている作業を止めないために、修正は待つべき」となる。ただ、個人的な回答をするなら「ちょっとした割り込みを楽しもう。ただし、ちょっとしたものに限る」と言いたい。そこに「割り込みにさらに割り込むことはしない」というルールも加えておこう(JimCoplienがこのルールを教えてくれた)。

別のコードを修正したくなったとき

プロダクトコードを追記した結果、テストのエラーが出ているが、追記した場所とは異なる箇所でプロダクトコードを変更しなければいけないことがわかったとき、 一度テストのエラーが出ない状態まで変更を巻き戻し、新しくプロダクトコードを変更する箇所のテストを先に書いてから実装の修正を行い、テストが通れば再び取り組んでいた問題に戻る。

(以下、本書の引用)

レッドバーが出ているときに新しくテストを加えるのは避けたいのだが、プロダクトコードを変更しなければならないときが来てしまった。テスト無しでコードを変更するわけにはいかない。手堅い方法は、レッドバーの原因になった変更を巻き戻し、グリーンバーに復帰するというものだ。グリーンバーに復帰したらequalsのテストを書いてから実装の修正を行い、再び取り組んでいた問題に戻る。

実装内部で使うヘルパークラスのテストは書かない

実装のテストが通れば内部のヘルパークラスの動作が正しいことが保証されるのでヘルパークラスのテストを書かなくてもいい場合がある。

(以下、本書の引用)

今回はPairクラスのテストを書かない。なぜかというと、いまはリファクタリングの過程としてPairクラスを抽出している途中だからだ。リファクタリングが完了してすべてのテストが通るようになったら、それでPairクラスも同時にテストされていると見なしてよい。

TDDで作成されたテストはステートメントカバレッジが高くなるがパフォーマンステストなどの代替にはならない

TDDを行うとプロダクトコードの命令文全体のうち、テストを実施した割合は100%に近くなり、システム開発を続けるためには有用なものになる。 ただし、パフォーマンステスト、負荷テスト、ユーザービリティテストの代替になるわけではない。