はじめに
テストコードの価値を高めるためには、
テスト対象を分析し、
その分析結果に応じてリファクタリングや
テストコードの削除・改善などを適切に行う必要があります。
今回はテスト対象を分類する方法と、
その分類結果に応じて何をすれば
テストコードの価値をさらに高めることができるか。
についてまとめました。
テスト対象を分析して4つに分類する
テスト対象は2つの視点で分類できます。
- コードの複雑さとドメインにおける重要性
- 協力者オブジェクト(依存)の数
コードの複雑さは、
テスト対象の分岐の数(判断を行う箇所)の数で計測でき、
ドメインのにおける重要性は、
ビジネスの問題領域におけるテスト対象の重要性で決まります。
このような箇所には、
重点的に単体テストを書く必要があります。
逆にビジネス的に重要でない、
複雑でない、
ような箇所にテストコードを形だけ書いている場合、
その単体テストに価値はあまりありません。
テストコードはただ書けばいい、
ただコード網羅率を100%にすればいい
というわけではありません。
価値のあるテストコードを、
必要な箇所にだけ書くことが重要です。
一方で、
テスト対象の協力者オブジェクト(依存)が多い場合、
テストコードはテストの準備で、依存をモックしたり、
テストコードが長く・複雑になるため
保守しずらいテストコードになります。
ただ、依存の種類によっては、
例えば値や値オブジェクトのように
テストの準備が不要なものもあり、
それらは依存の数に含めずに分析します。
このように、
テスト対象をコードの複雑さ・ドメインの重要性、
協力者オブジェクトの数
の2つの観点で4つに分類できます。
4つの分類の特徴についてもう少し見ていきます。
ドメイン・モデル/アルゴリズムに分類されるテスト対象
ビジネス的に重要だったり、
ビジネスとは直接関係ないが複雑だったりするロジックです。
そのため、その部分には特に退行に対する保護を強く備えておく必要があります。
ここに分類された部分に対してのテストコードは、
非常にコスパが良いです。
テスト対象として実行されるコードが複雑なロジックや重要なロジックであるため、
そのコードを検証することで退行に対する保護がより強く備わります。
一方で、
テスト対象となるコードに協力者オブジェクトが含まれることがあまりないため、
テスト実行のためにモックなどの準備が不要で、
シンプルな単体テストコードになり、
テストコードの保守コストも低く抑えられます。
コントローラーに分類されるテスト対象
このコード自体は複雑でビジネス的に重要なことは行わず、
ドメインモデル、外部システム連携、データベースアクセス
などを行う複数のコンポーネントを連携させて、
1つのビジネス的なユースケースを実現します。
ここに分類されるテスト対象には、
単体テストではなく統合テストを書きます。
取るに足らないコードに分類されるテスト対象
setterやgetter、ガード節などのないコンストラクタなど、
複雑さがなく、ビジネス的に重要でもないような箇所です。
もしそのような箇所を
テスト対象にしていたらそのテストは削除します。
テストコードという負債を増やしても、
得られる価値がないからです。
そのような箇所にとりあえずテストコードを書くことは、
テストスイート全体の価値を下げることにつながるので、
削除しなければなりません。
個人的には、
ドメイン層だけどメチャクチャシンプルな
値オブジェクトやエンティティ
(ビジネス的には重要と分類され、複雑さはほぼゼロ)
へのテストもシンプルなうちは書かない。
という方針で良いと考えています。
過度に複雑なコードに分類されるテスト対象
コントローラーとして
データベース連携、外部システム連携などを行うのに加えて
ドメインロジックなどのビジネス的に重要で複雑なロジックも
持つようなコードです。
ここに分類されたテスト対象に対して、
そのままテストコードを書こうとしてはいけません。
テストが難しいのと、
そもそもテスト対象の設計ミスに対しての
根本原因を解決できないからです。
ここに分類されたら、
テスト対象の設計を見直し、
ドメイン・モデル/アルゴリズムとコントローラーに
分解するリファクタリングから始める必要があります。
過度に複雑なコードをリファクタリングしてテストコードの価値を高める
過度に複雑なコードは責務を2つ持っているので、
設計的にも歪で、テストもしずらいです。
なので、
細かいリファクタリングのテクニックは色々ありますが、
ドメイン・モデル/アルゴリズムとコントローラに
責務を分解するというのが基本的なアプローチです。
悪い例ですが、
自分が現場で実際に見たテストコードでは
過度に複雑なコードに対して、
テストコードでなんとかしようとして
統合テストをとてつもない数作って、
自動テスト実行に1時間近くかかるようなテストスイートができあがりました。
こんな感じ・・・
過度に複雑なコードは、
テストコードだけでなんとかするアプローチだと、
自分が体験したようなことになるので、
みなさんは注意してください!!
最近だと、クリーンアーキテクチャやオニオンアーキテクチャなどを採用して、
アーキテクチャでガチガチに単一責任原則に従わせて、
過度に複雑なコードができないようになっていて、
テストコードを書く際には悩まされないケースもあるとは思いますが、
自分の体感的にはまだまだ、
現場でテストコードを書く際に過度に複雑なコードに悩まされるケースも多いので
参考になれば幸いです。