Re:TDD を理解するためのまとめ

TDDを理解するためのまとめ - Logic Dice
を読んで、いい機会だと思って

テスト駆動開発入門

テスト駆動開発入門

  • 作者: ケントベック,Kent Beck,長瀬嘉秀,テクノロジックアート
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2003/09
  • メディア: 単行本
  • 購入: 44人 クリック: 1,026回
  • この商品を含むブログ (156件) を見る

を買って、実際に「Part 1 Money オブジェクトの例」を写経してみた。
んで、感じたことなどを。
あ、あくまで今の時点での考えなので、変なとこあったら指摘してくだしあ!

Red から Green、Green から Red

ある意味では残念な事なのですが、大抵のTDDの説明に記述されている、「RedからGreenに変わることが気持ちいい」という、その感覚が分からないのです。

TDDを理解するためのまとめ - Logic Dice

この気持ちは分からなくもない。
たまには Red から Green になって「おっしゃ!」と思うことはあっても、それは「気持ちいい」というわけではないし・・・
ここら辺は個人差なのだろうと割り切っておいた方がいいかもしれない。セールストーク、リップサービスの類の可能性もあるし、もしかすると伝言ゲーム的なノリかもしれないし。


ただまぁ、Red から Green の流れより、Green からの意図しない Red にほっとする、というのはよくある。
あぁ、テストがあってよかった、みたいな*1


それに、実は Eclipse

  • 高速ビュー On
  • エラー/障害時にのみアクティブにする On

と設定してるから、Green とか目にしないんだよねぇ・・・
VisualStudio に至っては、TestDriven.NET を使ってるから、そもそも色がないし。

自明な実装

TDDの紹介では、大概の場合に置いて小さなメソッドのテストが行われます。そこで説明されている事項は、説明のためとは言え、明らかに易しすぎるのです。その程度の事なら、テストを書く前に実装をしたい、と思ってしまうのです。

TDDを理解するためのまとめ - Logic Dice

これはまぁまさに説明のためで・・・
重要なのは、「この手順で実装できる」という安心感で、実際に本に書いてある通りの回りくどい方法を毎回毎回取る必要はない。
ただし、テストに関してはほぼ常に先に書く方がいいのかな、なんて思ったりする。

後で書くテストと先に書くテスト

確かに、先にテストを書くことで以降のテストのためのコードは残ります。後からテストを書くのを「やっぱりやめた」と言って、テストコードを書かないことを防ぎます。そして、そのテストを残す事がテストファーストの利点と言われます。
しかし、そう言われても、何か釈然としなかったのです。


その理由の1つは、例ではテストを単一メソッドに対して行っており、そのテストからスケルトンコード(REDを出力する実装)を生成していたことです。
メソッドはクラスの一部であり、そのクラスの振る舞いを定義します。
しかし、メソッドは詳細です。ただ1つのメソッドでは、クラス全体の振る舞いを知ることは出来ません。
故に、クラスという大ではなく、メソッドという小に焦点を当てているにも関わらず、そこからクラス全体をテストするためのコードを生み出そうとしているように見えることが、釈然としませんでした。
(注:記事の投稿時に確かめてみると、おそらくテスト駆動開発入門ではこれとは違う方法で生成を行っています。この本のPart1は詳細に進めすぎていて、逆に全体が見えてこない印象を受けましたが…)


そのような小をテストすることが単体テストである、と言われたらそれまでなのですが……

TDDを理解するためのまとめ - Logic Dice

テストを残すことは利点ではあるけど、その理由付けが違うんじゃないかなぁ。
テストを先に書く、というのは、インターフェイス*2と主な振る舞いを決定する意味合いが強くて、テストを後に書く、というのは、書いたものに対しての単体テストという意味*3しか持たない。
だから、TDD で記述するテストを「単体テスト」とひとまとめにしてしまうのはちょっと違和感がある。
TDD で記述するテストは、網羅性は求めていなくて、YAGNI に則って最小限の入出力分のテストさえあればいいんだと思う。
もちろん、それだけだと単体テストにはならないから、後で単体テスト用のテストは追加しなければならないんだけど。


なんで、わんくまで言ってたような入出力を網羅したようなテストって、実は TDD 的ではないんじゃないかなぁ、というのが自分の考え。
入出力を網羅したようなテストって、ある程度中がどうなってるか分からないと書けないというか、最初からそこまでがっちがちに振る舞いを決定する必要はないというか・・・
例えば入出力を網羅したようなテストを最初に書いたとすると、その後可能なリファクタリングってどう考えても狭まる。
出来なくはないけど、リファクタリング作業がとても重いものになってしまう。
リファクタリングのためのテストなのに、リファクタリングを阻害してしまうのは本末転倒だと思う。


TDD によりテスト容易性は確保されるので、TDD せずに後で単体テストを作るより、TDD で開発してあとで単体テストも作る方がテストは楽になるような気がする。
や、もちろんテストを意識して設計することでもそれは達成できるんで、結局は使う人の腕次第・・・?

テストの寿命

仮に「入出力を網羅したようなテストはある程度実装を意識する必要がある」が正しいとすると、それらのテスト群は TDD により作成したテスト群よりも、寿命が短いと言うことになる。
なぜなら、実装を意識している以上、リファクタリング時 (つまり実装の変更時) にそれらのテスト群は一斉に変更が必要となる可能性が高いから (変更しなかった場合、一斉に Red となる)。
こういう寿命の短いテストは、やはりリファクタリングには邪魔にしかならないため、最初から作り込む必要はないだろう。


また、いつでも簡単に切り捨てることが出来るように、TDD により作成した一連のテストとは別の場所・別のファイルにしておくということも考えられる。
ルートディレクトリレベル、ディレクトリレベル、ファイルレベル、ファイル内での記述位置レベル、どの程度切り離すかは分からない。

シナリオベースのテスト:TDD によるテスト、メソッドベースのテスト:単体テスト

とか、そんなことを思ったりした。
いや、こんなりはっきり分かれるわけではないだろうけど、少なくともシナリオベースのテストが (このエントリで言っているような) 単体テストであることは少ないように思う。
メソッドベースのテストが TDD によって生み出されることもないとは言わないけど、比率としてはシナリオベースのテストの方が多くなると思うし、多くあるべき。
やっぱりメソッドベースのテストというのは、入出力に重きを置くテストのように感じるし、事実そうだと思う。

ナイトリー (デイリー) ビルド時の回帰テストとコミット時の回帰テスト (スモークテスト)

ナイトリービルド時には時間による制限がないため、メソッドベースのテスト、つまりこのエントリでの単体テストを含めて実行すればいいが、コミット時はフィードバックがすぐにあることが重要なため、それほど時間をかけることが出来ない。
ここで、実行するテストの取捨選択が必要になってくるが、このテストのために TDD によるテストを基準に選択するのはどうだろうか。
基本的には TDD によるテストをすべて使用するのだが、それでも遅くなってきた場合は正常系のみに絞る、とか。

TDD による設計

シナリオテストによるクラス設計

ある意味では驚くべきことですが、シナリオテストを十分に考慮してプログラミングをすると、設計の質が上がりやすい傾向があります。
これは、そのクラスが外部からどのように使われるかを十分に吟味するためです。
自分がその新しく作られるクラスを使う視点に立つことで、変な使い方をしていないかをチェックすることができます。

TDDを理解するためのまとめ - Logic Dice

TDD は設計手法だ、というのはよく言われているし、実際、その通りだと思う。
BDD (Behavior Driven Development:振る舞い駆動開発) というものも、その側面を前面に押し出すために作られたような言葉で、個人的にはぶっちゃけ TDD と違いはないと思っている。
TDD は「テスト」という言葉を使っているように、どうしても従来のテスト (このエントリ (ry 単体テスト) を思い浮かべてしまうようで、それからの脱却という意味もあるんじゃないかな > BDD


あー、あと、「クラス設計」という言葉はあまり好きじゃない。本題にはあんまり関係ないけど。
まぁ、その話はまたの機会ということで・・・

エントリ全体

TDD のテストとしてメソッドベースのテストも考えているという点以外ではおおむね同意できた。
おおむね良いんじゃないかな。

ここからは・・・

超簡易版で本自体の感想 (感想?) でっす。

  • 固定値による実装→ 2 つ目のテストで一般化、というのは恣意的すぎる気がする
  • TODO リストの項目がどう出てくるのかの説明が足りないような気がする
  • ドキュメンテーションコメントはいつ書く?
  • アサーションはいつ書く?
  • コミットのタイミング迷う
  • コミット、TODO リスト、チケットの関係もどうするか迷う
  • P.55 で TODO リストから消えた項目の説明がない

あと実際に写経してみて分かったんだけど、IDE と相性が良いという割には・・・って、これは Eclipse の問題ですね、確実に。

*1:まぁただ、一気に大量に Red になると逆に悲しくなるけど

*2:言語仕様としての interface ではなくて、要は使い方

*3:品質を保証するためのテスト