オブジェクト指向設計実践ガイド ~Rubyでわかる 進化しつづける柔軟なアプリケーションの育て方
から、価値の高いテストについてまとめ
テストにより、自信を持って絶えず継続的にリファクタリングができます。効果 的なテストは、変更されたコードが継続して正しく振る舞うことを、全体のコストを上げること なく証明します。良いテストは、落ち着いてコードのリファクタリングを乗り越えます。コード ヘの変更によってテストの書き直しが強制されないように書かれているのです。
テストの意図
- バグを見つける
- テストは、唯一信用できる設計の仕様書
- 設計の決定を遅らせる
テストがインターフェースに依存している場合、その根底にあるコードは、奔放にリファクタ リングできます。テストは、 そのインターフェースが正しく振る舞い続けることを証明するので、
根底にあるコードを変更しても、テストの書き直しが求められることはありません。意図的にイ ンターフェースに依存することによって、テストを使い、設計の決定を安全に、かつ代償もなく、
遅らせることができます。
- 抽象を支える
テストは、あらゆる抽象のインターフェースを記録するものであり、したがっ て、背後を守ってくれる壁のようなものです。テストによって、設計の決定を遅らせることがで
き、任意の有益な度合いの抽象をつくることができます。
- 設計の欠陥を明らかにする
- 設計がまずければ、テストも難しい
テストのセットアップに苦痛が伴うのであれば、コードはコンテキストを要求しすぎています。1 つのオブジェクトをテストするために、ほかのオブジェクトをいくつも引き込まなければならな いのであれば、そのコードは依存関係を持ちすぎています。テストを書くのが大変なのであれば、 ほかのオブジェクトから見ても再利用が難しいでしよう。
何をテストするか
受信メッセージは、その戻り値の状態がテストされるべきです。送信コマンドメッセージは、送られたことがテストされるべきです。送信クエリメッセージは、テストするべきではありません。
- オブジェクトを、オブジェクトが応答するメッセージそのもの、かつそれだけであるかのように扱うことで、変更可能なアプリケーションを設計することができます。そして、この観点の重要性を理解してはじめて、最低限のコストで最大限の利益を生むテストを書けるようになるのです。
- パブリックインターフェースに定義されるメッセージを対象としたものを書くべき
- 最もコストが高く最も利用性の低いテストは、不安定 な内部の実装に結合すること
- テストは、オブジェクトの境界に入ってくる(受信する)か、出ていく(送信する)メ ッセージに 集中すべき
- 図9.2で は、Fooの受信メッセージがFooのパブリックインターフェースをつ くっています。 Fooは自身のインターフェースをテストする責任があり、メッセージの戻り値について表明 (ア サーション)をすることでそれを行っています。メッセージの戻り値について表明をするテスト は、状態のテストです。このようなテストは、一般的に、メッセージが戻す結果が、期待する値と 等しくなることを表明します。
- 送信メッセージの状態をテストする必要がないからといって、それらのテストをまったくしな くてよいというわけではありません。
- 多くの送信メッセージは、アプリケーションが依存するものに対して副作用 (フ ァイル の書き込みや、データベースヘの記録の保存、オブザーバーによってアクションが起こされるな ど)を持ちます。これらのメッセージは「コマンド(命令)」であり、それらが適切に送られたこと を証明するのは送り手のオブジェクトの責任
- メッセージが送られたことの証明は、振る舞いのテストであり、状態のテストではありません。振る舞いのテストには、メッセージが送られた回数と、使われた引数についての表明が含まれます。
受信メッセージのテスト
- 受信メッセージは、その実行によって戻される値や状態を表明することでテストされます。
- 考えられ得るすべての状況にお いて正しい値を返すことを証明する
送信メッセージのテスト
- コマンドメッセージを証明する
- メッセージが何を戻すかの表明をする のではなく、メッセージが送られるという期待を定義