199

I have a unit test where I have to mock a non-virtual method that returns a bool type

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 a mock object of XmlCupboardAccess class and I am trying to setup mock for this method in my test case as shown 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
}

But this line throws exception

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

Any suggestion how to get around this exception?

CDspace
  • 2,639
  • 18
  • 30
  • 36
Rahul Lodha
  • 3,601
  • 7
  • 25
  • 34

7 Answers7

291

Moq cannot mock non-virtual methods and sealed classes. While running a test using mock object, MOQ actually creates an in-memory proxy type which inherits from your "XmlCupboardAccess" and overrides the behaviors that you have set up in the "SetUp" method. And as you know in C#, you can override something only if it is marked as virtual which isn't the case with Java. Java assumes every non-static method to be virtual by default.

Another thing I believe you should consider is introducing an interface for your "CupboardAccess" and start mocking the interface instead. It would help you decouple your code and have benefits in the longer run.

Lastly, there are frameworks like : TypeMock and JustMock which work directly with the IL and hence can mock non-virtual methods. Both however, are commercial products.

Amol
  • 3,977
  • 1
  • 23
  • 24
  • 69
    +1 on the the fact that you should only mock interfaces. This question solved what I was running into, because I accidentally mocked the class and not the underlying interface. – Paul Raff Aug 30 '15 at 15:18
  • 1
    Not only does this solve the problem but it's good practice to use interfaces for all your classes that need testing. Moq is essentially forcing you to have good Dependency Inversion where as some of the other mocking frameworks allow you to get around this principle. – Xipooo Nov 16 '16 at 20:55
  • Would it be considered a violation of this principle if I have a fake implementation, e.g., FakePeopleRepository, of my interface, e.g., IPeopleRepository, and I'm mocking the fake implementation? I think IoC is still preserved because in my test setup I have to pass the fake object to my service class which takes the interface in its constructor. – paz Feb 13 '17 at 22:12
  • 1
    @paz The whole point of using MOQ is to avoid the fake implementation. Now consider how many variants of the fake implementation you would need to check the boundary conditions etc. In theory, yes, you could mock a fake implementation. But practically it sounds like a code smell. – Amol Feb 21 '17 at 06:38
  • Note that this error may actually occur with extension methods on interfaces, which may be confusing. – Dan Jul 18 '17 at 11:24
  • If you absolutely can't introduce an interface for whatever reason, you can set object properties on the object itself e.g. : mockObject.Object.PropertyA = "value"; – Will Apr 17 '19 at 15:28
48

As help to anybody that had the same problem as me, I accidentally mistyped the implementation type instead of the interface e.g.

var mockFileBrowser = new Mock<FileBrowser>();

instead of

var mockFileBrowser = new Mock<IFileBrowser>();
Ralt
  • 2,084
  • 1
  • 26
  • 38
7

Instead of mocking concrete class you should mock that class interface. Extract interface from XmlCupboardAccess class

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>();
Sashus
  • 411
  • 7
  • 8
5

Please see Why does the property I want to mock need to be virtual?

You may have to write a wrapper interface or mark the property as virtual/abstract as Moq creates a proxy class that it uses to intercept calls and return your custom values that you put in the .Returns(x) call.

Community
  • 1
  • 1
Bryida
  • 482
  • 6
  • 9
4

You'll get this error as well if you are verifying that an extension method of an interface is called.

For example if you are mocking:

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

You will get the same exception because .ValidateAndThrow() is an extension on the IValidator<T> interface.

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

Scotty.NET
  • 12,533
  • 4
  • 42
  • 51
2

In my case I was on Moq version lower than 4.16 and was using .Result syntax to mock an async method which is supported only starting with Moq 4.16

On mock version less than 4.16 following results into Invalid setup on a non-virtual member ... even while using Interface.

mock.Setup(foo => foo.DoSomethingAsync().Result).Returns(true);

On Moq version lower than 4.16 use following

mock.Setup(foo => foo.DoSomethingAsync()).ReturnsAsync(true);

For more see Async Methods Moq Wiki at Github

TheCrazyProgrammer
  • 7,918
  • 8
  • 25
  • 41
-13

Code:

private static void RegisterServices(IKernel kernel)
{
    Mock<IProductRepository> mock=new Mock<IProductRepository>();
    mock.Setup(x => x.Products).Returns(new List<Product>
    {
        new Product {Name = "Football", Price = 23},
        new Product {Name = "Surf board", Price = 179},
        new Product {Name = "Running shose", Price = 95}
    });

    kernel.Bind<IProductRepository>().ToConstant(mock.Object);
}        

but see exception.

krlzlx
  • 5,752
  • 14
  • 47
  • 55
Borat
  • 7
  • 1
  • 5
    Could you provide an explanation of your solution? Also, "see exception..." is left hanging. Can you expand on this? – amadan Oct 28 '16 at 14:05