インターフェイスなしでクラスをモックするにはどうすればよいですか?


82

私はWindows7でC#を使用して.NET4.0に取り組んでいます。

モックを使っていくつかのメソッド間の通信をテストしたいと思います。唯一の問題は、インターフェースを実装せずにやりたいということです。それは可能ですか?

モックオブジェクトに関する多くのトピックといくつかのチュートリアルを読んだだけですが、それらはすべて、クラスではなく、インターフェイスをモックするために使用されていました。RhinoとMoqのフレームワークを使おうとしました。


1
これらのツールが「IInterfaces」を排他的に使用するという観点から作成されていることは本当に痛いです。
AR

4
インターフェイスベースのDIを使用していることを前提に作成されています。これは最近のかなり標準的なパターンです。
Maess 2013

残念ながら、そのパターンは不変タイプの「パターン」と競合します:(
Matthew Watson

回答:


67

偽造する必要のあるメソッドをvirtual(プライベートではなく)マークするだけです。次に、メソッドをオーバーライドできる偽物を作成できるようになります。

を使用new Mock<Type>し、パラメーターのないコンストラクターがない場合は、上記の呼び出しの引数としてパラメーターを渡すことができます。param Objects


1
これは、私がモックしたいすべてのクラスのインターフェースを作成する必要があるのか​​どうか疑問に思います。インターフェイスがない場合、モックに具象クラスを使用することはできませんか?
orad 2015年

14
@orad実際、私は最初にクラスを作成する傾向があり、一般的な機能を分解する必要がある場合にのみインターフェイスを作成します。
Justin Pihony 2015年

次に、指定された型を期待するオブジェクトにモックを渡すにはどうすればよいですか?モック 'new Mock <MyType>'を作成し、それをMyTypeを期待するオブジェクトに渡そうとすると、「Mock <MyType>をMyTypeに変換できません」というエラーが発生します。
ニュートリノ

2
モックを「varmyMock = new Mock <MyType>()」として定義する場合は、モックをmyMock.Objectとして使用するクラスに渡す必要があります。
ニュートリノ

4
主な問題は、パラメーターのないコンストラクターがなく、閉じたConcreteクラスのパラメーター化されたコンストラクターがパブリックでない場合に発生します。(ここでは、「閉じた」とは、外部パッケージを意味します)。次に、インターフェイスを実装したり、そのメソッドを仮想化したり、パラメーター化されたコンストラクターを使用したりすることはできません。
AbhilashPokhriyal20年1

22

ほとんどのモックフレームワーク(MoqおよびRhinoMocksを含む)は、モッククラスの代わりにプロキシクラスを生成し、定義した動作で仮想メソッドをオーバーライドします。このため、モックインターフェース、または具象クラスまたは抽象クラスの仮想メソッドのみをモックできます。さらに、具象クラスをモックする場合、モックフレームワークがクラ​​スをインスタンス化する方法を認識できるように、ほとんどの場合、パラメーターなしのコンストラクターを提供する必要があります。

コードでインターフェースを作成することを嫌うのはなぜですか?


107
それは、テストフレームワークの技術的な制限がなければ、完全に不要な大量のインターフェイスでコードベースを詰まらせるからですか?
BlueRaja-Danny Pflughoeft

9
「リーチは把握を超える」という表現を聞いたことがあるでしょう。それが、開発者が常に不平を言っている理由です。C#言語は、単体テストを念頭に置いて設計されていません。そのため、無意味なインターフェイスや仮想メソッドが大量に散らかっていない限り、モックの依存関係を挿入するのは非常に困難です。おそらく誰かがすぐにユニットテストが簡単な言語を発明するでしょう。それまでに、私たちは不平を言う何か他のものがあるでしょう。
ジョンヘンケル

13
インターフェースと仮想メソッドの唯一の目的がテストを提供することである場合、それらを雑然と見なしているのは私だけではないことを知ってうれしいです。
aaaaaa 2017

13
「唯一の目的はテストを提供することです」が、テスト可能なコードを作成することはあなたにとって重要ではありませんか?
MakkyNZ 2017

13
「なぜあなたのコードでインターフェースを作成することを嫌うのですか?」このオブジェクトを作成しておらず、コードにアクセスできないためです。インターフェイスを実装していない、所有していない閉じたオブジェクトのモックを作成する必要があります。
Sean Worle 2018

16

MoQを使用すると、具体的なクラスをモックできます。

var mocked = new Mock<MyConcreteClass>();

ただし、これにより、virtualコード(メソッドとプロパティ)をオーバーライドできます。


1
私はそれを試しましたが、テストプロジェクトを実行すると、プログラムが例外をスローします:「クラスのプロキシをインスタンス化できません」「パラメーターのないコンストラクターが見つかりませんでした」。
Vinicius Seganfredo 2013

2
コンストラクターのパラメーターをMock <>コンストラクターに渡すだけです。例new Mock<MyConcreteClass>(param1, anotherParam, thirdParam, evenMoreParams);
BozhidarStoyneff19年

1
クラスのインターフェースを作成してみませんか?
ロバートペリー

11

そのクラスのインターフェースを作成する方が良いと思います。そして、インターフェースを使用して単体テストを作成します。

そのクラスにアクセスできない場合は、そのクラスのアダプターを作成できます。

例えば:

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を使用してクラスのモックを簡単に作成できます。

それがうまくいくことを願っています。


4
これはメンテナンスにはひどいです。RealClassに新しいメソッドを追加する場合は、それをIReadClassAdapterとRealClassAdapterにも追加する必要があります。トリプルエフォート!より良い解決策は、RealClassの各パブリックメソッドに「virtual」キーワードを追加することです。
ジョンヘンケル2017

12
@JohnHenckelRealClassにアクセスできないと思います。したがって、「仮想」メソッドを追加することは、私の意見ではオプションではありません。実際のクラスにアクセスできる場合は、新しいクラスへのインターフェイスを直接実装することをお勧めします。これがベストプラクティスだと思います。
Anang Satria 2017

ありがとう。これは、アクセス権のないクラスをモックするための1つの正当な解決策のようです。「ばかげた」コードがたくさんあるとしても、「不適切な環境」でコードを実行するには、これが必要です
MichaelSpannbauer20年

7

標準のモックフレームワークはプロキシクラスを作成しています。これが、技術的にインターフェースと仮想メソッドに限定されている理由です。

「通常の」メソッドもモックしたい場合は、プロキシ生成の代わりにインストルメンテーションで動作するツールが必要です。たとえば、MSMolesとTypemockはそれを行うことができます。しかし、前者には恐ろしい「API」があり、後者は商用です。


そのパブリックメソッドで通常のクラスをモックできますか?
SivaRajini 2018

7

テスト対象のクラスを変更できない場合、私が提案できる唯一のオプションは、MS Fakeshttps //msdn.microsoft.com/en-us/library/hh549175.aspxを使用することです。ただし、MSFakesはVisualStudioの一部のエディションでのみ機能します。


2

悪化した場合は、インターフェースとアダプターのペアを作成できます。代わりにインターフェースを使用するようにConcreteClassのすべての使用法を変更し、本番コードでは常に具象クラスの代わりにアダプターを渡します。

アダプターはインターフェースを実装するため、モックもインターフェースを実装できます。

メソッドを仮想化したり、インターフェイスを追加したりするよりも足場になりますが、具象クラスのソースにアクセスできない場合は、バインドから抜け出すことができます。


1

私が取り組んだ古くてレガシーなプロジェクトの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

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