1. ホーム
  2. c#

[解決済み] Invalid setup on a non-virtual (overridable in VB) member..." というメッセージのExceptionが発生するのはなぜですか?

2022-01-30 11:28:33

質問

ユニットテストで、bool型を返す非仮想的なメソッドをモックしなければならないことがあります。

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>())

この例外を回避する方法について、何かご提案があれば教えてください。

解決方法は?

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

もうひとつ考慮すべきことは、"CupboardAccess"にインターフェースを導入し、代わりにそのインターフェースのモッキングを始めることです。これは、コードの分離を助け、長い目で見たときにメリットがあります。

最後に、.NETのようなフレームワークがあります。 タイプモック ジャストモック これらは IL で直接動作するため、非仮想的なメソッドをモックすることができます。しかし、どちらも商用製品である。