2

I'm new to Moq

I read a lot about Moq testing and that you shouldn't test your mock object, instead you should use Moq to stub dependencies and make it to act like you want to. But now I am asking myself, how can you test if a method be called from another method in the same class, like this code:

public class A // --> class i want to test
{
  public virtual void TestMethod() // --> does it call testmethod2
  {
    TestMethod2();
  }

  public virtual void TestMethod2()
  {
    // Do something
  }
}

I thought I can write the Unittest like this:

[TestMethod]
public void MyTestMethod()
{
  Mock<A> aMock = new Mock<A>();
  aMock.Verify(o => o.TestMethod2(), Times.Once);

  aMock.TestMethod();

  aMock.VerifyAll();
}

But is this valid? Thank you for all good answers!

StuartLC
  • 104,537
  • 17
  • 209
  • 285
Trace
  • 51
  • 10
  • Most likely there is no reason to mock at all, see: https://stackoverflow.com/questions/56078171/when-to-use-mock-objects-in-unit-tests/56102108#56102108 – Dirk Herrmann Sep 04 '19 at 20:58

1 Answers1

0

Moq is only able to mock out methods which are virtual (or provide mock implementations for interfaces). If you try a Setup or Verify on a non-virtual member, you'll get the error

Invalid verify on a non-virtual member: m => m.TestMethod2()

In your case, you would need to change TestMethod2 to virtual, i.e.

public virtual void TestMethod2()

Which can then be tested:

var aMock = new Mock<A>();

aMock.Object.TestMethod();

aMock.Verify(m => m.TestMethod2(), Times.Once);

As you've suggested, testing whether a class calls methods internal to itself is a smell, indication that you're either

  • Testing internal implementation detail (e.g. if TestMethod2() was private, it's none of our business to even know about it).
  • Or, an indication that the Class / System under test is in need of refactoring into multiple classes, which should be loosely coupled, and hence can be isolated and better testable.

Note

  • You can't Verify a call before you've invoked the method on the SUT that you want to test, i.e. move the Verify to after the invocation of .TestMethod() as I've done.
  • Although you could change your code to use the Setup + VerifyAll approach to testing, i.e. ensuring that everything you've setup is actually invoked:

aMock.Setup(m => m.TestMethod2());

aMock.Object.TestMethod();

aMock.VerifyAll();

There is however debate around whether the usage of VerifyAll violates AAA principals (since you're also in effect specifying the Verify criteria in the Arrange piece), and I've also found that this approach makes it impossible to refactor and DRY up Mock setups in large scale tests, and you also lose some of the finer level of checking (e.g. Times.Once).

StuartLC
  • 104,537
  • 17
  • 209
  • 285