ユニットテストには依存性注入が不可欠ですか?


55

単体テストに依存性注入(DI)の使用は不可欠ですか?

テストできるようにコードを分離する別の方法は考えられません。また、私が今まで見たすべての例では、このパターンを使用しています。それは唯一の実行可能なオプションであるか、または他の選択肢があるからでしょうか?


5
依存性注入は必須ではありませんが、Inversion of Controlのより広い概念は必須です。
ジェレミーハイラー

ここにスケールについて言わなければならないことがあります。レイヤー数が非常に少ない小さなコードベースがある場合、DIは役に立ちません。
JBキング

@JBKing小規模なコードベースがある場合、レイヤーやユニットテストは必要ありません
Sklivvz 14年

1
コードをテスト可能にするには、多くの設計上の決定が必要です。テストの作成を開始して調べてください。
ネイサンクーパー

回答:


42

DIを使用すると、単体テストがはるかに簡単になります。ただし、DIなしで単体テストを作成することはできます。DIが普及する前に、多くの単体テストがすでに作成されています。(もちろん、これらのいくつかはDIと同じか非常によく似たテクニックを使用しましたが、それは派手な名前を持っていることを知らずに:-)

私自身は、DIについて学ぶ前に、例えばインターフェースや工場をたくさん使ってきました。実際のファクトリクラス名は、構成ファイルから読み取られたか、引数としてSUTに渡された可能性があります。

別のアプローチは、シングルトン(または一般的にグローバルにアクセス可能なデータ)を使用することです。はい、それは一般的に多くの人(自分を含む)に推奨されていないことを知っています。それでもそれはありシングルトンは、テストケース特有の問題ではありません静的構成データが含まれていますが、生産およびテスト環境の間で異なっている場合は特に、特定の状況で生存可能。もちろん、既知の問題があるため、使用できる場合はDIの方が優れています。しかし、多くの場合(たとえば、レガシーシステムでは)できません。

そういえば、レガシーコードを効果的に使用するには、レガシーコードをテストでカバーするための多くのトリックについて説明します。これらの多くは優れたものではなく、長期的な解決策を意図したものでもありません。しかし、そうしないとテストできないシステムに対して最初の貴重な単体テストを作成できます。これにより、リファクタリングを開始し、最終的に(とりわけ)DIを導入できます。


同意しました。DIはオブジェクトのモックに特に役立ちます。しかし、テストではDIが役に立たない多くのシナリオがあります。
ケモダ

@Kemodaは、たとえば何が好きですか?
BЈовић

@VJovicたとえば、スタンドアロンオブジェクト。私は、いくつかの引数を取り、いくつかのことを実行しますが、別のコンポーネントに依存しないメソッドを考えます(したがって、DIは必要ありません)。
ケモダ

@Kemoda関数型プログラミングを記述しているようで、DIを使用しているようです。メソッドのパラメーターとして依存関係を注入しています。
エリックディートリッヒ

3
@huggie、なぜ実装の詳細がここで漏洩するのですか?通常、注入された依存関係はインターフェイスの背後に隠されており、全体のポイントは、この依存関係の実際の実装が実際の運用クラスであるかモックであるかをクライアントクラスが認識していないことです。そのインスタンス化はクライアントクラスの外部で行われ、既製のインスタンスのみが表示されます。
ペテルトーレック

56

デカップリングは単体テストに不可欠です。DIは、デカップリングを実現するための優れた方法です。


17
質問に決して答えない、非常に真実の声明。
トラビス

10

使用しているテクノロジに応じて、DIを使用せずに依存関係を分離できます。たとえば、.NETの世界では、Molesを使用すると、DIパターンなしで依存関係を分離できます。

そうは言っても、これらの分離フレームワークは、外部依存関係(ファイルシステム、データベースなど)のあるコードの状況向けに作成され、意図されていると思います。つまり、これができるという事実は、彼または彼女がすべきだという意味ではありません。

依存性注入により、単体テストが可能になりますが、オブジェクトのコードを変更せずにオブジェクトの動作を変更することもできます(オープン/クローズ原則)。そのため、テスト可能なコードだけでなく、柔軟なコードが生成されます。私は一般に、保守可能/柔軟なコードとテスト可能なコードの間に強い相関関係があることを発見しました。


3
または、Molesを使用すると、マジックを使用してテストしているため、クリーンで十分にファクタリングされたテスト可能なコードがあると考えることができます。
ワイアットバーネット

@WyattBarnettええ、とても本当です。Molesには、「とにかくこのポリモーフィズムとオープン/クローズされたものをすべて必要としているのは誰か?!?」
エリックディートリッヒ

1
Molesはfakesに置き換えられました。fakesページの「Fakesフレームワークは、開発者が単体テストでダミー実装を作成、保守、注入するのに役立ちます」とDIのように聞こえます。
ログイン

1
@Signあなたのリンクは、「Fakesフレームワークを使用して、シールされたタイプの非仮想メソッドおよび静的メソッドを含む、あらゆる.NETメソッドをシムすることができます」とも述べています。分離フレームワークをDIと組み合わせて使用​​できるという事実は、それら DIであること意味するものではありません。
エリックディートリッヒ

4

いいえ、DIは単体テストに不可欠ではありませんが、多くの場合に役立ちます。

ファクトリーまたはロケーターを使用して、DIの場合と同じようにテストできます(それほどエレガントではなく、より多くのセットアップが必要になります)。

また、多くの呼び出しが依存関係ではなく関数に委任されるレガシーシステムでは、モックオブジェクトが重要になります。(モックオブジェクトは、適切なセットアップでも広範囲に利用できます)

テストがほとんど不可能なセットアップがあります。しかし、これは依存性注入が使用されるかどうかに基づいていません。


3

いいえ、依存性注入は単体テストには不可欠ではありません

依存性注入は、サブ処理を行うために依存クラスインスタンスを必要とするクラスがある場合に役立ちます。DIの代わりに、ビジネスメソッドのロジックをデータ収集部分(単体テスト不可)と単体テスト可能な計算部分に分離できます。

例(DIを使用)この実装は、Employee、Account、...に依存します。

 bool hasPermissionToTransferMoney(Employee employee, Account from, Account to, Money amount)
 {
     if (amount > 100 && employee.isStudent())
        return false;
     if (to.getOwner().getFamiliyName() == employee.getFamilyName() && ...
        return false; // cannot transfer money to himself;
     ...
 }

データ収集と計算の分離後:

 bool hasPermissionToTransferMoney(Employee employee, Account from, Account to, Money amount)
 {
     return hasPermissionToTransferMoney(employee.isStudent(), employee.getFamilyName(), to.getOwner().getFamilyName(), ...);
 }

 // the actual permission calculation
 static bool hasPermissionToTransferMoney(boolean isStudent, string employeeFamilyName, string receiverFamilyName, ...)
     if (amount > 100 && isStudent)
        return false;
     if (receiverFamilyName == employeeFamiliyName && ...
        return false; // cannot transfer money to himself
     ...
 }

計算部分は、依存性注入なしで簡単にテストできます。


1
  • ユニットテストには依存性注入は必須ではありません

  • 一方、ある実装を別の実装と交換する場合は、制御の反転が不可欠です。


0

はい、分離にDIを使用する代わりの方法があります。

1つの代替方法は、実際のオブジェクトではなくモックオブジェクトを返すようにテストから構成できるファクトリーまたはServiceLocatorを使用することです。

別の方法は、適切な分離フレームワークまたはモッキングツールを使用することです。そのようなツールは、ほぼすべての最新のプログラミング言語(少なくともJava、C#、Ruby、およびPython)に存在します。テスト対象のクラスが依存関係を直接インスタンス化する場合でも、テスト対象のクラスを他のクラス/タイプの実装から分離できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.