テストの考え方の違いについて
- テストを先に書くか、後に書くか
- テストを書くのか、例を書くのか
- テストを1個づつ書くか、一度にすべて書くか
- 外側から内側にテストを書くか(Outside-in)、内側から外側にテストを書くか(Inside-0ut)
- 状態の妥当性を確認するのか、振る舞いの妥当性を確認するのか
- フィクスチャを前もって用意するのか、テストごとに用意するのか
- 筆者の考え方
テストを先に書くか、後に書くか
- すでに完成したソフトウェアに対して、自動ユニットテストを書くのは大変な作業になる。
- テストを先に書くほうが、テスト対象のシステム設計がテスタブルになる。また、プロダクションコードがテストをパスするだけの必要最小限の処理に抑えられる。
テストを書くのか、例を書くのか
- テストを先に書くと言うと「存在しないソフトウェのテストをどのように書くのか?」という質問を受けることがある。その場合、example-driven development (EDD) について説明する。
- 例としてテストを書くことによって、テストが要求を満たしているかどうか確認できる。
テストを1個づつ書くか、一度にすべて書くか
- 「テストを少し書いて、プロダクションコードを書き、テストをまた少し書く…」というアプローチはインクリメンタル開発である。この方法は、テストが失敗した際に、どこに問題があるかをデバッガーをあまり使わなくても特定しやすい(Defect Localization)という利点がある。最後に変更を行った部分がテスト失敗の原因であることが多く、最後の変更内容は頭に残っているからである。
- 一方で、プロダクションコードを書く前に、フィーチャに必要なすべてのテストを特定することを好む開発者もいる。この方法は、クライアントやテスターの視点でテストを考えられる利点がある。
- 両者の妥協案として、空のテストメソッドをざっくり記載しておき、テストメソッドの中身は、一度に一つだけ記載していくという方法が考えられる。
- 上記は、ユニットテストにおける議論である。カスタマーテストにおいては、あるストーリーの開発が始まる前に、そのストーリーのテストをすべて用意することが自然である。
外側から内側にテストを書くか(Outside-in)、内側から外側にテストを書くか(Inside-0ut)
- Inside-outでは、最も内部的なコンポーネントから開発し、開発したコンポーネントをビルドしながら、徐々に外側のコンポーネント(ユーザーインターフェースなど)に向かって開発する。すでに開発済みのコンポーネントを利用するので、Test Stubs や Mock Objects の利用を避けることができる。
- Outside-inでは、最も外側のコンポーネントから開発する。その際に、内側のコンポーネントの仕様を考慮した Test Doubles を利用する。下位のクラスができると Test Doubles を取り除くことができるが、Test Doubles を保持し続けることで Defect Localization を少ないコストで維持できるという利点がある。
状態の妥当性を確認するのか、振る舞いの妥当性を確認するのか
- Statistは、テスト対象の初期状態を設定し、テスト実行後に期待する状態になっているかを検証する。
- Behaviroistは、テスト対象の開始と終了の状態だけでなく、テスト対象が依存するコンポーネントをどう呼んでいるかも含めて検証する。そのため、Mock Objects や Test Spies といったものを多用することになり、テストの独立性は高まるが、依存コンポーネントの変更などによるリファクタリングが困難になる側面もある。
フィクスチャを前もって用意するのか、テストごとに用意するのか
- Standard Fixture とは、1つ以上の Testcase Classes の すべてのTest Methods のために使われる汎用的なフィクスチャ生成方法である。Delegated Setup や Implicit Setup を使って、テストメソッドごとに Fresh Fixture としてセットアップできる。一方で、多くのテストで再利用される Shared Fixture としてセットアップもできる。
- アジャイルなアプローチでは、Minimal Fixture というものがある。事前に大規模なフィクスチャは用意せずに、各テストごとに必要最小限のフィクスチャを使うという考え方である。
筆者の考え方
- テストを先に書く!
- テストは例である!
- 普通はテストを1個づつ書くが、事前にすべてのテストをスケルトンとしてリストすることがある。
- 外側からテストすることで、次のレイヤで必要となるテストを明確化する。
- 通常は State Verification を使うが、コードカバレッジを良くするために Behavior Verificationに頼ることがある。
- 個々のテストごとにフィクスチャを用意する。
//