単体テストのメソッド
学習者テストって結局、何をどうやって検証するのが正解なの?戻り値を見ればいいの?
3つの単体テストの手法
- 出力値ベース(戻り値を検証)
- 状態変化ベース(状態の変化を検証)
- コミュニケーションベース(オブジェクト間のやり取りを検証)
出力値ベースの単体テスト
入力を与えて戻り値だけを検証する手法です。
この手法を使用できるケースは、基本的にテスト対象とその依存先オブジェクトの状態が変わらない場合です。 そのため検証値は戻り値のみです。
状態変化ベースの単体テスト
メソッド呼び出し後にオブジェクトや DBの状態が変化したかを検証する手法です。
コミュニケーションベースの単体テスト
テスト対象が外部オブジェクト(依存先)を正しく呼び出したかを検証する手法です。モックを使います。
3つの手法の比較
テストは出力値ベースが最もリファクタリング耐性が高く、保守コストが低くこの手法を用いるようにするべきです
| 手法 | リファクタリング耐性 | 維持性 | 保守コスト |
|---|---|---|---|
| 出力値ベース | ◎ 高い | ◎ 高い | ◎ 低い |
| 状態変化ベース | ○ 中程度 | ○ 中程度 | ○ 中程度 |
| コミュニケーションベース | △ 低い | △ 低い | △ 高い |
リファクタリング耐性とは、実装を変更しても(振る舞いが同じなら)テストが壊れない度合いです。
維持性とは、テストコードの読みやすさ・メンテのしやすさです。
保守コストとは、テストが壊れたときの修正コストや、テストコードを変更し続けるコストです。
出力値ベースのテストと関数型プログラミング
関数型プログラミングは、副作用を最小限に抑えるプログラミングパラダイムです。
そして出力値ベースのテストは対象が純粋関数であることが前提であるため、関数型プログラミングと相性が良いです。
関数型プログラミングとは、数学的関数を扱います。
数学的関数とは、入力に対して唯一の出力を返すものです。純粋関数とも呼ばれます。
逆に純粋関数でない隠れた出力があると、テストが壊れやすくなります
- 副作用
- オブジェクトの状態変化、DBへの書き込み
- 例外
- 例外が発生した場合の処理は、定義されていない出力といえます
- 状態の参照
- Date.now() のように、現在時刻を参照する関数は純粋関数ではありません
関数型プログラミングの導入で、ビジネスロジックと副作用の分離ができます
現在執筆中です。