xUnit Test PatternsのPART Ⅰ読んだ+テストに関する雑感
ようやくPART Ⅰまで読み終わったので忘れないうちに感想など。
xUTPという略語で呼ばれたり、読書会が開かれていたりと、ソフトウェアテスト本としてかなり評判が良い様子。
Kindle版を買ってみたものの
- ボリュームが多い(ハードカバー版だと900ページ超えとのこと)
- 日本語版がない
ということで長らく放置していた。
最近仕事でも自動テストを導入しつつあるので、ようやく読んでみた。
xUTPを読んで
全体の構成は、PART Ⅰで各パターンに触れながらテストに関する戦略や思想を解説、PART Ⅱ、PART Ⅲは各"Test Smell"やテストパターンの解説となっている。
(PofEAAのような構成)
とりあえずPART Ⅰに目を通しておけば良さそうだったので、PART Ⅰのみ読了。
PART Ⅰだけでも1ヶ月ぐらいはこの本を読んでいた気がする。
やはり英語はつらい。
内容的はxUnitに限らないのはもちろん、単体テストにも限らず自動テスト全般を対象にしていて、かなり網羅的。
ほとんどの話は誰もが一度は経験するようなあるある系なのだけれど、きちっとそれらに名前を付け、メリット・デメリットを整理しているところが良い。
整理した上で、"ベストプラクティスはこれだ"という話をするのでなくて、"こういったトレードオフになりますよ"という立ち位置なのも現実的で良かった。
結局は対象とするシステムやプロジェクトの性質や制約によってベストプラクティスは変わってくるものなので、変に正解を出されるよりも誠実だと思った。
あとは他の書籍でも使われるような言葉の定義("Mock"、"Test Double"など)も行っているので、その辺が気になる人にもいいと思う。
テストについて最近思うこと
さてテストを書こう、という時にいつも思うのが、"保守性の高いテストを書くにはどうしたらよいか?"ということ。
テストを書いてみたものの、その後メンテされず(せず)に二度と実行されない状態をしばしば見てきた。
テスト失敗しそうだからテスト実行しづらいし、新しいテストも書きづらいという悪循環。
特にテストの粒度について気になっていて、
など、考え出すともやもやが止まらない。
時と場合によるという話なのだろうが、自分なりの基準を持っておきたいところ。
xUTP を参考に
xUTPでもその辺りは当然取り上げられている。
単体テストの依存関係
Chapter4の"State or Bahavior Verification?"で、
- "statist"は、テスト対象がテスト後に望んだ状態になったかを検証する
- "behaviorist"は、テスト後の状態だけでなく、テスト対象がテスト中に依存コンポーネントをどう呼んでいるかも検証する
(No.2342/25720)
とある。
つまり、MockやStubをガンガン使うのが"behaviorist"ということ。
"behaviorist"なテストは、テストの独立性を高めるが、リファクタリングが行いづらくなる。
(No.2358/25720)
で、この"behaviorist"なテストをやりすぎると、"Overspecified Software(Chapter16)"になってしまう。
問題点は、
ソフトウェアが何を為すべきかでなく、ソフトウェアがどのように為すべきか、をテストが表現してしまう
(No.2571/25720)
こと。
上記を踏まえて極力MockやStubを使わないテスト(statist)とMockやStubを使ったテスト(behaviorist)の特徴を整理してみる。
statist
behaviorist
- 依存コンポーネントが正しくない動きをしてもエラーにならない
- 依存コンポーネントから独立してテストができる
- カバレッジを上げやすい
- リファクタリングで実装が変わるとテストが壊れる可能性がある
- 依存コンポーネントとの結合時にテストが失敗しやすい
で、この辺りの話の自分の結論としては、「MockやStubを使う特別な理由がない限りは使わない」。
特別な理由というのは、テストの実行速度だったり、Mockを使わないと検証できなかったり、外部サービスに依存していたり、など。
リファクタリングの頼りにテストを使いたいという気持ちが強いし、Mockを使ったテストを書いていると何をテストしているんだっけ?という気分になる。
著者の考えもこの路線のようだ。
単体テストと結合テスト
単体テストと結合テストも定義を用意してくれている。
多分に用語の問題を含むが、ここでは単純に単体テスト=UnitTest、結合テスト=ComponentTestとして考えている。
Unit testは、設計の結果としての1つのクラスまたはメソッドの振る舞いを検証する。 この振る舞いは、ビジネスロジックがクラスやメソッドにカプセル化されている場合を除き、要求に直接関係するものではない。 これらのテストは開発者が利用するために書かれる。 テストの形式で、そのユニットの振る舞いを要約して表現する。
Component testは、何らかのサービスを提供するクラスの集合コンポーネントを検証する。 テスト対象の範囲の点で、Unit testとCustomer testの中間に位置する。 "integration tests","subsystem tests"と呼ぶ人たちもいるが、それらは"システム全体の中の特定の一部のまとまったコンポーネントのテスト"とは異なったものを意味している。
(No.2733/25720)
このあたりの記述をもとに考えると、
単体テスト:1つのメソッドが意図通り実装できているかのテスト
結合テスト:複数クラスを組み合わせて実現する機能が正しく動作するかのテスト
といった観点で見ればよい気がした。
結論
テストについて考える時の前提知識または材料として、読んでおくとよいと思う。
テスト方針だったり、困っていることだったりに対してどういった考え方があるのか?というのが参考になる。
なんだかテストいまいちなんだけど、このやり方はしょうがないのかなー他にいいやり方あるのかなーという方におすすめ。
あとKindle版のが安いし用語にリンクが貼ってあっておすすめ。