0

I have a test which mocks a non-interface object with a constructor that takes parameters:

    [Test]
    public void Test()
    {
        var myObject = Substitute.For<MyObject>("param1", "param2");

        _sut.DoSomething(myObject);

        myObject.Received().SomeMethodWhichIsCalled();
    }

This passes and when I debug the test, I can see SomeMethodWhichIsCalled() on MyObject is executed correctly.

However I've now realised this assert does nothing, because I can add the below in:

    [Test]
    public void Test()
    {
        var myObject = Substitute.For<MyObject>("param1", "param2");

        _sut.DoSomething(myObject);

        myObject.DidNotReceive().SomeMethodWhichIsCalled();
        myObject.Received().SomeMethodWhichIsCalled();
    }

And the test still passes...

Is this a side effect of mocking classes and not interfaces?

Sefe
  • 13,731
  • 5
  • 42
  • 55
FBryant87
  • 4,273
  • 2
  • 44
  • 72

1 Answers1

1

You can mock only virtual members. The mocking-framework simply overrides the virtual members for you similar to this:

class MyMock : MyObject
{
    override void SomeMethodWhichIsCalled()
    {
        throw new Exception("Method was called");
    }
}

As your method is not virtual the framework isn´t able to override it and thus the actual method SomeMethodWhichIsCalled of MyObject is called, which never throws the exception.

There´s not much you can do about this, unless you can make the method virtual. You could try to access some internal state via reflection, but that highly depends on what SomeMethodWhichIsCalled does. In particular it´s only a dirty hack.

MakePeaceGreatAgain
  • 35,491
  • 6
  • 60
  • 111