背景
テストに関して以下疑問があった。
- テストを書く・書かないの判断基準はなにか。
- 課金系など、壊れると明らかに影響が大きいものは書くべきとわかるが、それ以外の場合の明確な基準が自分になかった。
- 適切なテストの書き方とは。
- 変更を加えた時に、変更と関係ないところでテストが落ちて、テストとして適切に機能していない時があった。
上記疑問は、良いテストの定義が自分になかったことが要因であり、そのことがこちらの本で解消されたので、それについて記載します。
定義
- 単体テスト
- 1単位の振る舞い検証するテスト。
- railsでいうmodelに対するテスト。
- 統合テスト
- 個々のソフトウェアモジュールを組み合わせて集合体として検証するテスト。
- railsでいうcontrollerに対するテスト。
- E2Eテストも統合テストに含まれる
良い単体テストの構成要素
- 退行(regression)に対する保護が備わっている
- リファクタリングへの耐性が高い
- 迅速なフィードバックが行われる
- 保守がしやすい
上2つについて自分が特に参考になったことを記載します。
下2つはそのままの意味なので説明は省略します。
退行(regression)に対する保護が備わっている
- 退行に対する保護がどれだけ備わっているかの評価軸
- テスト時に実行されるプロダクションコードの量(多いほど保護性能が高い)
- 量が多いほど、退行する可能性が高いため
- そのコードの複雑性(高いほど保護性能が高い)
- 複雑性が高いほど、退行する可能性が高いため
- そのコードが扱っている重要性(高いほど保護性能が高い)
- ビジネス的に重要な機能になるほど、持ち込まれたバグによって生じる被害が大きくなるため
- テスト時に実行されるプロダクションコードの量(多いほど保護性能が高い)
- テストを書くかどうかの基準
- 上記評価軸において、評価が高い場合に関しては、テストによるメリットとテストにより発生するコスト(書くための労力, 保守etc…)とを比較して、メリットが大きい場合にテストを書く(ここは主観で判断するしかないっぽい)
- 一方、上記評価が低い、取るに足らないコードに対してはテストをする価値はほとんどの場合ない。このようなコードは間違いが起こる可能性が低いため、退行を見つけ出すことがほとんどないため。価値が低いテストコードは負債なので、書かない方がいい(あるいは、手元でテストを書いて正常に動作することを確認したらテストを削除する。)。
リファクタリングへの耐性が高い
- リファクタリングをした時に壊れない = 偽陽性を引き起こさない ということ。
- 偽陽性に対して注意を払う必要がある理由は、偽陽性によってテストを実施すること自体の意味が損なわれてしまうため。
- 偽陽性を引き起こす多くの原因は、テストコードがプロダクションコードと密接に結びついていること。
- 対処法は、テストコードが検証する対象を、実行されたコードがもたらす最終的な結果にすること。その結果を得るための細かい手順である実装の詳細に目を向けないようにすること。
統合テスト
特徴
- 保守コストは単体テストよりも高くなる
- 協力者オブジェクト(処理上必要な他のクラスとのやり取り)の数が増えるにつれ、テストケースのコード量が増えるため
- 単体テストに比べて優れた退行に対する保護が備わる
- 単体テストよりも多くのコードを実行させることになるため
- リファクタリングへの耐性も単体テストよりも備わる
- プロダクションコードとの結びつきが、単体テストよりも直接的でなくなるため
テスト方針
- 1件のハッピーパスと、単体テストでは検証できないすべての異常ケースを行うべき。
- 検証する内容のほとんどを単体テストに持たせることで、テスト全体の保守コストを少なくし、それと同時にビジネスシナリオごとに1, 2件の包括的な結合テストを行うことで、システム全体が正しく機能することに自信を持てるようになる。