web-dev-qa-db-ja.com

「非仮想(VBでは上書き可能)メンバーの設定が無効です...」というメッセージが表示されて例外が発生するのはなぜですか?

ブール型を返す非仮想メソッドをモックする必要があるという単体テストがあります

public class XmlCupboardAccess
{
    public bool IsDataEntityInXmlCupboard(string dataId,
                                          out string nameInCupboard,
                                          out string refTypeInCupboard,
                                          string nameTemplate = null)
    {
        return IsDataEntityInXmlCupboard(_theDb, dataId, out nameInCupboard, out refTypeInCupboard, nameTemplate);
    }
}

それで、私はXmlCupboardAccessクラスのモックオブジェクトを持っていて、以下に示すように私のテストケースでこのメソッドのためにモックを設定しようとしています

[TestMethod]
Public void Test()
{
    private string temp1;
    private string temp2;
    private Mock<XmlCupboardAccess> _xmlCupboardAccess = new Mock<XmlCupboardAccess>();
    _xmlCupboardAccess.Setup(x => x.IsDataEntityInXmlCupboard(It.IsAny<string>(), out temp1, out temp2, It.IsAny<string>())).Returns(false); 
    //exception is thrown by this line of code
}

しかし、この行は例外を投げます

Invalid setup on a non-virtual (overridable in VB) member: 
x => x.IsDataEntityInXmlCupboard(It.IsAny<String>(), .temp1, .temp2, 
It.IsAny<String>())

この例外を回避するための提案はありますか?

155
Rahul Lodha

Moqは非仮想メソッドとシールクラスをモックすることはできません。モックオブジェクトを使用してテストを実行している間、MOQは実際には "XmlCupboardAccess"から継承したインメモリプロキシタイプを作成し、 "SetUp"メソッドで設定した動作をオーバーライドします。そして、C#で知っているように、何かが仮想としてマークされている場合にのみオーバーライドできます。これはJavaの場合ではありません。 Javaは、デフォルトではすべての非静的メソッドを仮想メソッドと見なします。

私があなたが考慮すべきであると私が思うもう一つのことはあなたの "CupboardAccess"のためのインターフェースを紹介して代わりにインターフェースをあざけり始めることです。それはあなたがあなたのコードを分離するのを助けてそしてより長い目で見て利益を得るでしょう。

最後に、次のようなフレームワークがあります。 TypeMock および JustMock これらはILと直接連携しているため、非仮想メソッドをモックすることができます。しかし、どちらも商品です。

240
Amol

私と同じ問題を抱えている人への助けとして、私は誤ってインターフェースの代わりに実装タイプをタイプミスしました。

var mockFileBrowser = new Mock<FileBrowser>();

の代わりに

var mockFileBrowser = new Mock<IFileBrowser>();
22
Ralt

を参照してください。モックしたいプロパティが仮想である必要があるのはなぜですか?

Moqは呼び出しをインターセプトして.Returns(x)呼び出しに設定したカスタム値を返すために使用するプロキシクラスを作成するため、ラッパーインターフェイスを作成するか、プロパティを仮想/抽象としてマークする必要があります。

4
Bryida

インターフェースの拡張メソッドが呼び出されていることを確認している場合も、このエラーが発生します。

例えば、あなたがあざけっているならば:

var mockValidator = new Mock<IValidator<Foo>>();
mockValidator
  .Verify(validator => validator.ValidateAndThrow(foo, null));

.ValidateAndThrow()IValidator<T>インターフェースの拡張であるため、同じ例外が発生します。

public static void ValidateAndThrow<T>(this IValidator<T> validator, T instance, string ruleSet = null)...

0
Scotty.NET

具象クラスをモックする代わりに、そのクラスインターフェースをモックするべきです。 Xml Cupboard Accessクラスからインタフェースを抽出する

public interface IXmlCupboardAccess
{
    bool IsDataEntityInXmlCupboard(string dataId, out string nameInCupboard, out string refTypeInCupboard, string nameTemplate = null);
}

そしての代わりに

private Mock<XmlCupboardAccess> _xmlCupboardAccess = new Mock<XmlCupboardAccess>();

への変更

private Mock<IXmlCupboardAccess> _xmlCupboardAccess = new Mock<IXmlCupboardAccess>();
0
Sashus