私はWindows7でC#を使用して.NET4.0に取り組んでいます。
モックを使っていくつかのメソッド間の通信をテストしたいと思います。唯一の問題は、インターフェースを実装せずにやりたいということです。それは可能ですか?
モックオブジェクトに関する多くのトピックといくつかのチュートリアルを読んだだけですが、それらはすべて、クラスではなく、インターフェイスをモックするために使用されていました。RhinoとMoqのフレームワークを使おうとしました。
私はWindows7でC#を使用して.NET4.0に取り組んでいます。
モックを使っていくつかのメソッド間の通信をテストしたいと思います。唯一の問題は、インターフェースを実装せずにやりたいということです。それは可能ですか?
モックオブジェクトに関する多くのトピックといくつかのチュートリアルを読んだだけですが、それらはすべて、クラスではなく、インターフェイスをモックするために使用されていました。RhinoとMoqのフレームワークを使おうとしました。
回答:
偽造する必要のあるメソッドをvirtual
(プライベートではなく)マークするだけです。次に、メソッドをオーバーライドできる偽物を作成できるようになります。
を使用new Mock<Type>
し、パラメーターのないコンストラクターがない場合は、上記の呼び出しの引数としてパラメーターを渡すことができます。param Objects
ほとんどのモックフレームワーク(MoqおよびRhinoMocksを含む)は、モッククラスの代わりにプロキシクラスを生成し、定義した動作で仮想メソッドをオーバーライドします。このため、モックインターフェース、または具象クラスまたは抽象クラスの仮想メソッドのみをモックできます。さらに、具象クラスをモックする場合、モックフレームワークがクラスをインスタンス化する方法を認識できるように、ほとんどの場合、パラメーターなしのコンストラクターを提供する必要があります。
コードでインターフェースを作成することを嫌うのはなぜですか?
MoQを使用すると、具体的なクラスをモックできます。
var mocked = new Mock<MyConcreteClass>();
ただし、これにより、virtual
コード(メソッドとプロパティ)をオーバーライドできます。
new Mock<MyConcreteClass>(param1, anotherParam, thirdParam, evenMoreParams);
そのクラスのインターフェースを作成する方が良いと思います。そして、インターフェースを使用して単体テストを作成します。
そのクラスにアクセスできない場合は、そのクラスのアダプターを作成できます。
例えば:
public class RealClass
{
int DoSomething(string input)
{
// real implementation here
}
}
public interface IRealClassAdapter
{
int DoSomething(string input);
}
public class RealClassAdapter : IRealClassAdapter
{
readonly RealClass _realClass;
public RealClassAdapter() => _realClass = new RealClass();
int DoSomething(string input) => _realClass.DoSomething(input);
}
このようにして、IRealClassAdapterを使用してクラスのモックを簡単に作成できます。
それがうまくいくことを願っています。
標準のモックフレームワークはプロキシクラスを作成しています。これが、技術的にインターフェースと仮想メソッドに限定されている理由です。
「通常の」メソッドもモックしたい場合は、プロキシ生成の代わりにインストルメンテーションで動作するツールが必要です。たとえば、MSMolesとTypemockはそれを行うことができます。しかし、前者には恐ろしい「API」があり、後者は商用です。
テスト対象のクラスを変更できない場合、私が提案できる唯一のオプションは、MS Fakeshttps : //msdn.microsoft.com/en-us/library/hh549175.aspxを使用することです。ただし、MSFakesはVisualStudioの一部のエディションでのみ機能します。
悪化した場合は、インターフェースとアダプターのペアを作成できます。代わりにインターフェースを使用するようにConcreteClassのすべての使用法を変更し、本番コードでは常に具象クラスの代わりにアダプターを渡します。
アダプターはインターフェースを実装するため、モックもインターフェースを実装できます。
メソッドを仮想化したり、インターフェイスを追加したりするよりも足場になりますが、具象クラスのソースにアクセスできない場合は、バインドから抜け出すことができます。
私が取り組んだ古くてレガシーなプロジェクトの1つで、インターフェイスやベストプラクティスが含まれておらず、プロジェクトビジネスの成熟度のために、再構築やコードのリファクタリングを強制するのが難しいという問題に直面しました。 UnitTestプロジェクトでは、モックしたいクラスに対してラッパーを作成し、そのラッパーは、セットアップして操作したいすべての必要なメソッドを含むインターフェイスを実装していました。これで、実際のクラスの代わりにラッパーをモックできます。
例えば:
仮想メソッドを含まない、またはインターフェースを実装しない、テストするサービス
public class ServiceA{
public void A(){}
public String B(){}
}
moqへのラッパー
public class ServiceAWrapper : IServiceAWrapper{
public void A(){}
public String B(){}
}
ラッパーインターフェース
public interface IServiceAWrapper{
void A();
String B();
}
単体テストでは、ラッパーをモックできます。
public void A_Run_ChangeStateOfX()
{
var moq = new Mock<IServiceAWrapper>();
moq.Setup(...);
}
これはベストプラクティスではないかもしれませんが、プロジェクトルールがこのように強制する場合は、それを実行してください。また、不要なラッパーやアダプターでプロジェクトが過負荷にならないように、すべてのラッパーを単体テストプロジェクトまたは単体テスト専用に指定されたヘルパープロジェクト内に配置します。
更新: この回答は1年以上前のものですが、今年はさまざまなソリューションで同様のシナリオが数多く発生しました。たとえば、Microsoft Fake Frameworkを使用して、モック、フェイク、スタブを作成したり、インターフェイスなしでプライベートメソッドや保護されたメソッドをテストしたりするのはとても簡単です。読むことができます:https://docs.microsoft.com/en-us/visualstudio/test/isolating-code-under-test-with-microsoft-fakes?view = vs-2017