
t0mmy
学習履歴詳細
単体テストの考え方/使い方 9章 読了
やったこと
- 単体テストの考え方/使い方 9章 モックのベストプラクティス 読了
学んだこと
この章で取り扱うこと
- モックの価値を最大限に引き出す方法
- モックからスパイへの移行
- モックのベストプラクティス
ポイント
- モック化すべき対象と、モック化するべきではない対象
- モックとスパイの違い、およびスパイの利点
- モックのベストプラクティス
学び
- 単体テストでは、モックを使ってはならない
- 言い換えると、モックは、統合テストでのみ使用する
- モックでは、以下の二つを確認する事
- 想定している呼び出しが行われていること
- 想定していない呼び出しが行われていないこと
- 汎用I/Fと、ドメインモデルに特化したI/Fを分離する
- 言い換えると、ひとつのI/Fに、複数の責務を負わせないようにする
- この時、一つの具象クラスのために一つのI/Fを定義しているのであれば、I/Fを使用せず直接具象クラスを扱うことを検討する
気づき
- 「管理下にない依存」用のI/Fは、ドメインロジックと管理下にない依存を抽象化する役割もある
- AWS SDKの呼び出しをラップしたりは、無意識にやっていた
- 改めて、効果的な手法であることを再確認した
- 単体テストにモックを使用してはならない理由をつかめた
- 自プロダクトのテストにも改善の余地ありとみた
メモ
9.1 モックの価値を最大限に引き出す方法
モック化は、「管理下にない依存」に対してのみ実施すること。
- 「管理下にある依存」のモック化は、テストが実装の詳細に強く結びつき、テストが壊れやすくなる
モック化は、「アプリケーションの境界」に近いコンポーネントに対して行うと良い。
- リファクタリング耐性が向上する
- アプリケーションの境界に近いほど、実装の詳細との結びつきが弱くなるため
- より強い退行保護(バグ検出)能力が得られる
- 境界に近づくまでに、より多くのコンポーネントを経由することになる
- これは、より多くのコードをテストできることを意味する
モックからスパイへの置き換え
◇スパイ
モックと同じ、テストダブルの一種。
モックはフレームワークの助けを得て作成するのに対して、スパイは開発者が実装する。
別名、「手書きのモック」
モックと比較して、スパイは、以下の点で優れている。
- 実行結果を確認するコードを記述できる
- 記述したコードを再利用できる
- テストケースのコード量が減り、可読性が向上する
アプリケーションの境界に位置するテストダブルを作成する場合は、特に上記スパイの利点が大きくなる。
テストでは、プロダクションコードを信頼しない
監査人が、監査対象の人の言葉を鵜吞みにしないのと同じように、テストケースでは、プロダクションコードを信頼しない。
過度に信頼している例
あるメソッドの戻り値を検証せず、メソッドが呼び出されたことだけを検証している
また、テストは、プロダクションコードの影響を受けずに検証できる場所で行う必要がある。
9.2 モックのストプラクティス
モックの利用は統合テストに限定する
目的は、ビジネスロ ジッ クに関するコードと連携を指揮するコードとを分離すること。
- テストは、「プロセス外依存とのやりとり」または「ドメインの複雑さ」のどちらか一方だけをテストするべき
- 両方をテストしてはならない
モック化は、「管理下にない依存」に対してのみ行うべき。
「管理下にない依存」を扱うのはコントローラのみ。
つまり、モック化は、コントローラのテスト(≒統合テスト)でのみ行うべき。
モックは、「管理下にない依存」の数だけ用意する
言い換えると、「一テストにつきモックは一つだけ!」といった制約は存在しない。
モックに対して行われた呼び出し回数を常に確認する
言い換えると、モックに対して、以下の二つを必ず確認する。
- 想定する呼び出しが行われていること
- 想定していない呼び出しが行われていないこと
目的は、管理下にない依存との互換性を維持すること。
サードパーティーライブラリをモック化しない
サードパーティーライブラリ製のライブラリをモック化したい場合は、独自クラスでサードパーティーライブラリの処理をラップし、独自クラスに対してモック化すること。
この独自クラスは腐敗防止層として機能し、以下のメリットを享受できる。
- サードパーティーライブラリの複雑さを抽象化できる
- 必要な機能のみ公開できるようになる
- クラス名やメソッドを定義できる機会(≒名前を付ける機会)を得ることが出来る
- ドメインに合わせた、ドメイン用語を使用できるようになる
まとめ
- 「管理下にない依存」とのコミュニケーションを検証する場合、コントローラからその依存に向かう流れにて、最後のコンポーネントをモック化する
- スパイは別名「手書きのモック」
- システムの境界にあるクラスをモック化する場合は、スパイの方が優れている
- スパイであれば確認コードを記述でき、更にスパイの記述を使いまわすことができる
- テストでは、プロダクションコードの影響を受けない場所を構築し、そこでテストする必要がある
- プロダクションコードにて定義したリテラルや定数を使用しない
- 同義語反復なテストケース(なにも検証していない、無意味な確認)となりかねない
- 管理下にない依存は、全て同じレベルでの後方互換性が必要なわけではない
- メッセージの正確さではなく、メッセージの存在および特定の情報が含まれているかだけを検証したい場合など
- 単体テストでは、モックを使ってはならない
- モックは、管理下にない依存との通信でのみ使用する
- 管理下にない依存を扱うのはコントローラのみ
- コントローラをテストするのは統合テストのみ
- => モックは、統合テストでのみ使用する
- 言い換えると、単体テストでは、モックを使ってはならない
- 一つのテストケースで、モックを複数使っても問題ではない
- モックの数は、「管理下にない依存」の数で決まる
- モックを用いたテストでは、以下の二つを確認する
- 想定している呼び出しが行われていること
- 想定していない呼び出しが行われていないこと
- サードパーティーライブラリをモック化してはならない
- サードパーティーライブラリの処理をモック化したい場合は、サードパーティーライブラリのアダプターを作成し、アダプターに対してモック化する
2023年05月02日(火)
2.0時間