これをMoqでm笑できますか?
-
10-07-2019 - |
質問
私はいくつかの外部依存関係のモックに取り組んでいますが、コンストラクタに別のサードパーティクラスのインスタンスを取り込むサードパーティクラスで問題が発生しています。 SOコミュニティが何らかの方向性を与えてくれることを願っています。
SomeLibraryClass
のモックインスタンスをコンストラクターに取り込む SomeRelatedLibraryClass
のモックインスタンスを作成したい。どうすれば SomeRelatedLibraryClass
をこのようにモックできますか?
レポコード...
テストコンソールアプリケーションで使用しているMainメソッドを次に示します。
public static void Main()
{
try
{
SomeLibraryClass slc = new SomeLibraryClass("direct to 3rd party");
slc.WriteMessage("3rd party message");
Console.WriteLine();
MyClass mc = new MyClass("through myclass");
mc.WriteMessage("myclass message");
Console.WriteLine();
Mock<MyClass> mockMc = new Mock<MyClass>("mock myclass");
mockMc.Setup(i => i.WriteMessage(It.IsAny<string>()))
.Callback((string message) => Console.WriteLine(string.Concat("Mock SomeLibraryClass WriteMessage: ", message)));
mockMc.Object.WriteMessage("mock message");
Console.WriteLine();
}
catch (Exception e)
{
string error = string.Format("---\nThe following error occurred while executing the snippet:\n{0}\n---", e.ToString());
Console.WriteLine(error);
}
finally
{
Console.Write("Press any key to continue...");
Console.ReadKey();
}
}
これは、1つのサードパーティクラスをラップしてMoqを許可するために使用したクラスです。
public class MyClass
{
private SomeLibraryClass _SLC;
public MyClass(string constructMsg)
{
_SLC = new SomeLibraryClass(constructMsg);
}
public virtual void WriteMessage(string message)
{
_SLC.WriteMessage(message);
}
}
これは、私が使用しているサードパーティクラスの2つの例です(これらを編集することはできません):
public class SomeLibraryClass
{
public SomeLibraryClass(string constructMsg)
{
Console.WriteLine(string.Concat("SomeLibraryClass Constructor: ", constructMsg));
}
public void WriteMessage(string message)
{
Console.WriteLine(string.Concat("SomeLibraryClass WriteMessage: ", message));
}
}
public class SomeRelatedLibraryClass
{
public SomeRelatedLibraryClass(SomeLibraryClass slc)
{
//do nothing
}
public void WriteMessage(string message)
{
Console.WriteLine(string.Concat("SomeRelatedLibraryClass WriteMessage: ", message));
}
}
解決
AFAIK、あなたがモックアウトしようとしているクラスが仮想またはインターフェースでない場合-Moqでモックすることはできません。サードパーティのライブラリがクラスを実装していない場合、運が悪いと思います。
他のヒント
ゲートウェイパターンを使用することをお勧めします。 SomeRelatedLibraryClassに直接依存するのではなく、インターフェイスISomeRelatedLibraryClassGatewayを作成します。 ISomeRelatedLibraryClassGatewayの同じシグネチャのメソッドで呼び出す必要があるSomeRelatedLibraryClassのすべてのメソッドを公開します。
public interface ISomeRelatedLibraryClassGateway {
void WriteMessage(string message);
}
次に、すべての呼び出しをサードパーティクラスにルーティングする実装を作成します。
public class SomeRelatedLibraryClassGateway : ISomeRelatedLibraryClassGateway {
private readonly SomeRelatedLibraryClass srlc;
public SomeRelatedLibraryClassGateway(SomeRelatedLibraryClass srlc) {
this.srlc = srlc;
}
void ISomeRelatedLibraryClassGateway.WriteMessage(string message) {
srlc.WriteMessage(message);
}
}
SomeRelatedLibraryClassに依存するアプリのクラスは、代わりにISomeRelatedLibraryClassGatewayに依存できるようになり、このインターフェイスは簡単にモックできます。 SomeRelatedLibraryClassGatewayクラスには、実際には単体テストは必要ありません。コールをパススルーするだけです。機能テストでテストする必要がある が、モックなしで機能テストを行うことができます。
これが役立つことを願っています。