Coder Perfect

What is the meaning of the Exception “Invalid setup on a non-virtual (overridable in VB) member…”?

Problem

I have to simulate a non-virtual method that returns a bool type in a unit test.

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);
    }
}

So I have an XmlCupboardAccess mock object, and I’m trying to set up a mock for this method in my test case as seen below.

[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
}

However, there is an exception in this sentence.

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

Is there a way to get around this exception?

Asked by Rahul Lodha

Solution #1

Non-virtual methods and sealed classes are not mockable by Moq. MOQ provides an in-memory proxy type that inherits from your “XmlCupboardAccess” and overrides the behaviors you set out in the “SetUp” function when you run a test using a mock object. In C#, you can only override something if it is designated as virtual, which is not the case in Java. By default, Java considers all non-static methods to be virtual.

Another thing I think you might think about is creating an interface for your “CupboardAccess” and mimicking it instead. It would assist you in decoupling your code and provide long-term benefits.

Finally, frameworks such as TypeMock and JustMock deal directly with the IL, allowing them to mock non-virtual methods. Both, on the other hand, are commercial goods.

Answered by Amol

Solution #2

I unintentionally mistyped the implementation type instead of the interface as an aid to anyone who experienced the same difficulty as me, e.g.

var mockFileBrowser = new Mock<FileBrowser>();

instead of

var mockFileBrowser = new Mock<IFileBrowser>();

Answered by Ralt

Solution #3

Rather than mocking the real class, imitate the class interface. XmlCupboardAccess class’s interface should be extracted.

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

And instead of

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

change to

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

Answered by Sashus

Solution #4

Please look into it. Why is it necessary for the property I wish to mock to be virtual?

Because Moq produces a proxy class that it uses to intercept calls and deliver your custom values that you placed in the, you may need to construct a wrapper interface or declare the property as virtual/abstract. Call to Returns(x).

Answered by Bryida

Solution #5

If you try to verify that an interface’s extension method is called, you’ll get this error.

If you’re mocking, for example:

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

Because, you’ll get the same exception. ValidateAndThrow() is an IValidatorT> interface enhancement.

void public static ValidateAndThrowT>(this IValidatorT> validator, T instance, string ruleSet = null, this IValidatorT> validator, this IValidatorT> validator, this IValidatorT> validator, this IValidatorT> validator, this IVa

Answered by Scotty.NET

Post is based on https://stackoverflow.com/questions/21768767/why-am-i-getting-an-exception-with-the-message-invalid-setup-on-a-non-virtual