依存性注入の解決と単体テスト
-
03-07-2019 - |
質問
アプリケーションの単体テスト時に依存関係の注入を学習しようとしていて、問題に遭遇しました。
コンソールアプリケーションを作成しており、コンテナはMain()で作成および初期化され、get-property
でProgram.Container
として使用できるため、アプリケーション内のどこでもProgram.Container.Resolve<..>()
を呼び出すことができます。
次のようなServiceValidatorクラスがあります:
public class ServiceValidator
{
private readonly IConfiguration _configuration;
private readonly IService _service;
public ServiceValidator(IConfiguration configuration, IService service)
{
_configuration = configuration;
_service = service;
}
私が使用する別のクラスで
ServiceValidator serviceValidator = Program.Container.Resolve<ServiceValidator>();
serviceValidator.VerifyVersion();
セットアップされていないため、ユニットテストで問題が発生するのはProgram.Container.Resolve
の呼び出しです。
コンテナで解決を呼び出すのは悪い習慣ですか? Main()
でServiceValidatorインスタンスを作成し、オブジェクトを渡すことができますが、次のメソッドに渡されるだけのオブジェクトの多くのパラメーターが発生するので、馬鹿げているようです。
そのため、クラス内でResolveを呼び出すことは許容できると思いますが、ユニットテスト用にコンテナを構成する必要があります。コンテナをプログラムクラス以外の場所に移動する必要がありますか?何をお勧めしますか?
問題があれば、UnityとC#を使用しています
ありがとう:-)
解決
コンテナで解決を呼び出すのは悪い習慣ですか? Main()でServiceValidatorインスタンスを作成してオブジェクトを渡すこともできますが、次のメソッドに渡されるオブジェクトのパラメーターが大量に発生するため、馬鹿げているようです。
依存性注入をすべて使用する場合、オブジェクトに大量のパラメーターを渡す必要はありません。各オブジェクトのコンストラクターは、それ自体が直接使用する依存関係のみをパラメーターとして持つ必要があります-その直接依存関係の推移的依存関係については知りません。
したがって、ServiceValidatorを必要とするクラスXがある場合、クラスXにはServiceValidator型のコンストラクターパラメーターがあります。あるクラスYがクラスXを使用する場合、クラスYはタイプXのコンストラクターパラメーターを持ちます。YはServiceValidatorについて何も知らないので、あるクラスからServiceValidatorを渡す必要はありません。別の-それが使用される唯一の場所はXを構築するときであり、それは多くの場合DIフレームワークによって、または手書きファクトリの1つの場所でのみ行われます。
詳細情報へのリンク:
- http://martinfowler.com/articles/injection.html
- http://www.youtube.com/watch?v=RlfLCWKxHJ0 -オブジェクトの受け渡しに関するあなたの質問は、19:20 <!> quot; DIに関する神話<!> quot; から回答されています
他のヒント
通常、mainなどの場所でコンテナからの依存関係を解決するための呼び出しを許可していますが、それでも最小限に抑えるようにしています。次に、テストクラスの初期化メソッドでコンテナーを構成します。コンテナを呼び出す必要があるテストクラスの偽の実装で初期化しています。
コンテナの初期化を必要とするものを呼び出さないテストクラスは、コンテナを無視して偽物を使用することはできません。通常、これらのインスタンスではモックを使用します。
Microsoft Service Locator も使用するため、依存関係が私が取っていることは、特定のコンテナではなく、.NET Frameworkからのものです。これにより、自家製のコンテナであっても好きなものを使用できます。
静的クラスをコンテナの初期化子として使用できます。 BootStrapper.csのようなもので問題ありません。その後、コードとテストの両方でクラスメソッドを参照できます。
まあ、技術的にやっているのは、クラスのサービスの場所です。
しばらく前にこの記事を読んだことを覚えています:
http://martinfowler.com/articles/injection.html
クラスでは、Resolveを使用しようとしません。必要なときにコンテナを介してオブジェクトを作成します。単体テストでは、モックライブラリとスタブクラスを使用します。
問題は、Mainメソッドをテストしようとしているという事実にあります。この方法は、単体テストでは事実上不可能です。
次の理由により、Mainメソッドを単体テストしないことが最善であると主張します。
- 最新の単体テストの重点は設計に関するものです
- 単体テストの構成への依存を最小限に抑える必要があります。設定は、煙または統合テストでテストできます。