トップ回答者
依存クラスが多い場合のユニットテスト

質問
-
お世話になります。
依存クラスが多い場合のユニットテストの書き方について悩んでいます。
言語はC#5.0です。
ユニットテストはVisual Studio 2013 professionalの単体テスト機能を使っています。
製品自体はN層アーキテクチャで構築しています。
ビジネスロジック層からデータアクセス層の呼び出しはDIを使っているので、データアクセス層のモックを作ってテストしています。そのため、データアクセス層に直接依存するような、ビジネスロジック層の最下層のクラスのテストはモックの作成も容易です。
しかし、クラスA→クラスB→クラスC→・・・と呼び出し階層が深いクラスがあります。このようなクラスは、最終的に依存するデータアクセス層クラスがかなりの数にのぼり、たくさんのデータアクセス層モックを作らなければなりません。
必要なデータアクセス層モックの洗い出しも、依存クラスをひたすら調べていくしかなく、作業効率が悪い状況です。
このような場合、一般的にどのような戦略がとられるのでしょうか。
やはり、ビジネスロジック層の中でもDIを用いて、依存クラスのモックを作れるようにしているのでしょうか。
その場合、ビジネスロジック層の全てのクラス間の依存関係を、DIで解決できるように設計するのか(全部のクラスのinterfaceを定義する…メンテが大変)、それとも何らかのルールに基いて、一部のクラスのみ注入可能なように設計するのか、方針があるのでしょうか。
何かご存知の方おられましたら、情報をいただけると助かります。
- 編集済み femp 2014年12月12日 2:20 表現の修正
回答
-
> クラスA→クラスB→クラスC
上記のときにクラスAをテストするために、クラスBをモック化した場合で説明させて頂きます。
一般的にというお話ですと、モックがクラスCに依存する必要がないので、テスト時においてはクラスA→モックBという関係でテストすることになるかと思います。更に、クラスBをテストするときはクラスB→モックCといった具合ですね。クラスAをテストする際にクラスBをモックとするならば、当然ながらテストの目的がクラスAのみになります。モックBはブラックボックス、ハードコードされた値、クラスCに非依存で良いのではないでしょうか。
実装のお話ですと、
> DIで解決できるように設計するのか(全部のクラスのinterfaceを定義する…メンテが大変)
とあるように、クラスBのモック化、さらにはクラスBをテストするときのクラスCのモック化と考えていった場合、インターフェイスが大量に必要になります。
逃げ道として、クラスBに変更を入れることが可能、かつ、許容される場合、Moqライブラリが使用できます。クラスAテスト時に依存するクラスBの関数を動的にオーバーライドして返り値を定義できます。しかし、関数がvirtualである必要があります。
クラスBに変更入れることが不可能、または、virtualが許容されない場合、Visual Studioのプレミアム、アルティメット以上であればMicrosoft Fakesが使用できます。こちらはvirtualでない関数も差し替えることができます。
これらのライブラリの詳細は下記が参考になります。
http://www.buildinsider.net/hub/bioff/o3
> Moq & Fakes Frameworkを使った実践的ユニットテスト [スライド&動画] - Build Insider
Visual Studioエディションについては製品比較の[テストツール] > [Microsoft Fakes (単体テストの分離)]を参照してください。
http://www.visualstudio.com/products/compare-visual-studio-products-vs
すべての返信
-
> クラスA→クラスB→クラスC
上記のときにクラスAをテストするために、クラスBをモック化した場合で説明させて頂きます。
一般的にというお話ですと、モックがクラスCに依存する必要がないので、テスト時においてはクラスA→モックBという関係でテストすることになるかと思います。更に、クラスBをテストするときはクラスB→モックCといった具合ですね。クラスAをテストする際にクラスBをモックとするならば、当然ながらテストの目的がクラスAのみになります。モックBはブラックボックス、ハードコードされた値、クラスCに非依存で良いのではないでしょうか。
実装のお話ですと、
> DIで解決できるように設計するのか(全部のクラスのinterfaceを定義する…メンテが大変)
とあるように、クラスBのモック化、さらにはクラスBをテストするときのクラスCのモック化と考えていった場合、インターフェイスが大量に必要になります。
逃げ道として、クラスBに変更を入れることが可能、かつ、許容される場合、Moqライブラリが使用できます。クラスAテスト時に依存するクラスBの関数を動的にオーバーライドして返り値を定義できます。しかし、関数がvirtualである必要があります。
クラスBに変更入れることが不可能、または、virtualが許容されない場合、Visual Studioのプレミアム、アルティメット以上であればMicrosoft Fakesが使用できます。こちらはvirtualでない関数も差し替えることができます。
これらのライブラリの詳細は下記が参考になります。
http://www.buildinsider.net/hub/bioff/o3
> Moq & Fakes Frameworkを使った実践的ユニットテスト [スライド&動画] - Build Insider
Visual Studioエディションについては製品比較の[テストツール] > [Microsoft Fakes (単体テストの分離)]を参照してください。
http://www.visualstudio.com/products/compare-visual-studio-products-vs
-
ありがとうございます。
Fakesはすごいですね・・・とても欲しいですが、VSPremium以上となると手が出ない・・・
Moqは結構有名みたいですが、これを使われる皆さんは、
①ユニットテスト対象クラスについて全てインタフェースを作る
②ユニットテスト対象クラスのメソッドを全てvirtualにする
のどちらかの方針を採っているということなんでしょうか。
①は単純に面倒、②は何となく設計的に抵抗があるんですが、考えてみたらJavaはデフォルトがvirtualですし、手間を考えるとMoq使って②の方針を採るのが現実的な落とし所?
ひとまずそんな方針にしてみようと思います。
ありがとうございました。 -
Fakesはすごいですね・・・とても欲しいですが、VSPremium以上となると手が出ない・・・
もう解決済みと思いますが、上記コメントに反応しました。
利用可能な方の条件でいくつか制約はありますが、Visual Studio Community 2013 なら、Visual Studio の全機能を無償で使用可能です。
質問者さんが利用できない状況下だとしても、このスレッド覗いた方の今後の参考にして頂ければと思い、一応コメントさせていただきます。MSDNフォーラムのヘルプは以下ご覧ください http://social.technet.microsoft.com/wiki/contents/articles/7359.forums-help-faq.aspx
-
利用可能な方の条件でいくつか制約はありますが、Visual Studio Community 2013 なら、Visual Studio の全機能を無償で使用可能です。
そのページの Q&A の 2 つ目、「Q: Visual Studio Community と Visual Studio Professional の違いはなんですか?」をお読みください。
結論を書くと、Visual Studio Community では Fakes を利用できません。
- 編集済み AzuleanMVP, Moderator 2014年12月18日 13:06