フレームワークのWebサイトをモックする例のほとんどは、インターフェイスをモックすることです。私が現在使用しているNSubstituteとしましょう。それらのモックの例はすべて、インターフェイスをモックすることです。
しかし実際には、一部の開発者が具象クラスを模擬するのを見ました。具象クラスを模擬することをお勧めしますか?
理論的には、具象クラスをあざける問題はまったくありません。 (キーワードinterface
ではなく)論理インターフェースに対してテストを行っていますが、その論理インターフェースがclass
によって提供されているかinterface
によって提供されているかは関係ありません。
実際には、.NET/C#はこれを少し問題にします。 .NETモックフレームワークについて述べたように、私はあなたがそれに制限されていると仮定します。
.NET/C#では、メンバーはデフォルトで非仮想であるため、動作をモックする(つまり、クラスから派生し、すべてのメンバーをオーバーライドしてテスト固有のものを行う)プロキシベースのメソッドは、メンバーを明示的にマークしない限り機能しません。 virtual
として。これは問題を引き起こします:単体テストで完全に安全であることを意図したモッククラスのインスタンスを使用しています(つまり、実際のコードを実行しない)が、すべてがvirtual
であることを確認していないと、最終的には実際のコードとモックされたコードが混在して実行されます(これは、常に実行されるコンストラクターロジックがあり、更新される他の具体的な依存関係がある場合はさらに悪化します)。
これを回避するにはいくつかの方法があります。
interfaces
を使用します。これは機能し、 NSubstituteのドキュメント で助言しますが、実際には必要ない可能性があるインターフェイスでコードベースが肥大化する可能性があるという欠点があります。間違いなく、コードに優れた抽象化が見つかれば、当然、テストできる再利用可能なインターフェイスがきちんと整ってしまいます。私はそれがそのようにパンアウトするのを見たことはありませんが、YMMVです:)最後のアイデアに対して提出された一般的な不満は、「偽の」継ぎ目を介してテストしているということです。コードを拡張してコードの動作を変更するために通常使用されるメカニズムの外に出ます。これらのメカニズムの外に出る必要があるということは、設計の厳格さを示している可能性があります。私はこの議論を理解していますが、別のインターフェースを作成することのノイズがメリットを上回るケースを見てきました。潜在的な設計上の問題を認識しておくことが問題だと思います。設計の剛性を強調するためにテストからのフィードバックが必要ない場合、それらは優れたソリューションです。
最後に、テストでユニットのサイズを変更する方法を説明します。通常、1つのユニットとして1つのクラスがあります。ユニットとしていくつかのまとまりのあるクラスがあり、そのコンポーネントの周りに明確に定義された境界として機能するインターフェースがある場合は、多くのクラスをモックする必要がなく、より安定した境界をモックするだけで済みます。これにより、テストがより複雑になる可能性があります。利点としては、機能のまとまりのあるユニットをテストし、そのユニットの周りに堅固なインターフェースを開発することが推奨されるという利点があります。
お役に立てれば。
更新:
3年後、気が変わったことを認めたいと思います。
理論的には、モックオブジェクトの作成を容易にするためだけにインターフェイスを作成するのは好きではありません。実際には(私はNSubstituteを使用しています)、複数のパラメーターを持つ実際のクラスをモックするよりもSubstitute.For<MyInterface>()
を使用する方がはるかに簡単です。 Substitute.For<MyCLass>(mockedParam1, mockedParam2, mockedParam3)
、各パラメーターは個別にモックする必要があります。その他の潜在的な問題は NSubstituteのドキュメント で説明されています
私たちの会社では、現在推奨されているプラクティスはインターフェースを使用することです
元の答え:
同じ抽象の複数の実装を作成する必要がない場合は、インターフェースを作成しないでください。それが David Tchepakによって指摘された なので、実際に必要とされない可能性のあるインターフェースでコードベースを肥大化したくないでしょう。
http://blog.ploeh.dk/2010/12/02/InterfacesAreNotAbstractions.aspx から
疎結合を可能にするためにクラスからインターフェースを抽出しますか?その場合、おそらくそれらを実装する インターフェイスと具象クラスの間の1:1の関係 があります。それはおそらく 良い兆候ではない であり、 再利用された抽象化の原則(RAP) に違反しています。
特定のインターフェイスの実装が1つしかないのはコードの匂いです
ターゲットがテスト容易性である場合、 上記のDavid Tchepakの回答 の2番目のオプションを使用します。
ただし、すべてを仮想化する必要があるとは思いません。代替するメソッドのみを仮想化するだけで十分です。また、メソッドが仮想であることをメソッド宣言の横にコメントを追加して、単体テストのモッキングの代わりに使用できるようにします。
ただし、インターフェースではなく具象クラスの置換にはいくつかの制限があることに注意してください。例えば。 NSubstituteの場合
注:クラスを作成して使用すると、望ましくない副作用が生じる可能性があるため、クラスの再帰的な代用は作成されません。
。
問題はむしろです。なぜでしょうか。
これが役立つシナリオがいくつかあります。
具象クラスの実装はまだ完了していないか、それを実行した人が信頼できません。そのため、クラスを指定どおりに模擬し、コードをテストします。
また、データベースアクセスなどを行うクラスをモックするのにも役立ちます。テストデータベースがない場合は、常に定数であるテストの値を返すことができます(クラスをモックすることで簡単です)。
それが推奨されるということではなく、他に選択の余地がなければこれを行うことができるということです。
通常、適切に設計されたプロジェクトは、個別のコンポーネントのインターフェースの定義に依存しているため、他のコンポーネントをモックすることにより、コンポーネントを個別にテストできます。しかし、あなたがレガシーコード/変更できないコードを使用していて、それでもクラスをテストしたい場合は、選択の余地がなく、批評することはできません(あなたがこれらのコンポーネントをインターフェースに切り替えてみて、その権利を拒否されました。