Why am I getting an Exception with the message “Invalid setup on a non-virtual (overridable in VB) member…”?

前端 未结 6 1570
野的像风
野的像风 2020-11-27 12:44

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

public class XmlCupboardAccess
{
    public bool IsDataEntityInXmlCupbo         


        
相关标签:
6条回答
  • 2020-11-27 13:15

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

    0 讨论(0)
  • 2020-11-27 13:17

    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>();
    
    0 讨论(0)
  • 2020-11-27 13:20

    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>();
    
    0 讨论(0)
  • 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.

    0 讨论(0)
  • 2020-11-27 13:36

    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.

    0 讨论(0)
  • 2020-11-27 13:37

    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.

    0 讨论(0)
提交回复
热议问题