Search code examples
c#unit-testingmoq

Can I use moq Mock<MyClass> to mock a class, not an interface?


Going through https://github.com/Moq/moq4/wiki/Quickstart, I see it Mock an interface.

I have a class in my legacy code which does not have an interface. When I Mock<MyClass>, I get the following exception:

Additional information: Can not instantiate proxy of class: MyCompnay.Mylegacy.MyClass.

How can I use Moq to mock class from legacy code?


Solution

  • It is possible to Mock concrete classes

    [TestClass]
    public class PlaceholderParserFixture
    {
    
      public class Foo
      {
         public virtual int GetValue()
         {
            return 11;
         }
      }
    
      public class Bar
      {
         private readonly Foo _foo;
    
         public Bar(Foo foo)
         {
            _foo = foo;
         }
    
         public int GetValue()
         {
            return _foo.GetValue();
         }
      }
    
      [TestMethod]
      public void MyTestMethod()
      {
         var foo = new Mock<Foo>();
         foo.Setup(mk => mk.GetValue()).Returns(16);
         var bar = new Bar(foo.Object);
    
         Assert.AreEqual(16, bar.GetValue());
      }
    
    }
    

    but,

    • It must be a public class
    • The method to be mocked must be virtual

    The messages I got for:

    Making the class internal

    Castle.DynamicProxy.Generators.GeneratorException: Type MoqFixture+Foo is not public. Can not create proxy for types that are not accessible.

    or, having a non-virtual method

    System.NotSupportedException: Invalid setup on a non-virtual (overridable in VB) member: mk => mk.GetValue()

    do not match your cannot instantiate message, so something else seems to be wrong.

    If you do not have a default constructor on the mocked object you can get that error message

    e.g.

    public class Foo
    {
    
        private int _value;
        public Foo(int value)
        {
           _value = value;
        }
    
        public virtual int GetValue()
        {
            return _value;
        }
    }
    

    one can get around this by passing values into the Mock<> ctor

    e.g.

    var foo = new Mock<Foo>(MockBehavior.Strict, new object[] { 11 });