Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Verifying protected abstract methods are called using Moq

Suppose I have the following class:

public class TestBase
{
  public bool runMethod1 { get; set; }

  public void BaseMethod() 
  {
    if (runMethod1)
      ChildMethod1();
    else 
      ChildMethod2();
  }

  protected abstract void ChildMethod1();
  protected abstract void ChildMethod2();
}

I also have the class

public class ChildTest : TestBase
{
  protected override void ChildMethod1()
  {
    //do something
  } 

  protected override void ChildMethod2()
  {
    //do something completely different
  }

}

I'm using Moq, and I'd like to write a test that verifies ChildMethod1() is being called when I call BaseMethod() and runMethod1 is true. Is it possible to create an implemention of TestBase with Moq, call BaseMethod() and verify that ChildMethod was called on the Moq implementation?

[Test]
public BaseMethod_should_call_correct_child_method()
{
  TestBase testBase;

  //todo: get a mock of TestBase into testBase variable

  testBase.runMethod1 = true;

  testBase.BaseMethod();

  //todo: verify that ChildMethod1() was called

}
like image 378
Lance Fisher Avatar asked Jul 16 '26 17:07

Lance Fisher


2 Answers

You can also set the expectation/setup as Verifiable and do without a strict mock:

  //expect that ChildMethod1() will be called once. (it's protected)
  testBaseMock.Protected().Expect("ChildMethod1")
    .AtMostOnce()
    .Verifiable();

  ...

  //make sure the method was called
  testBase.Verify();

Edit This syntax does not work in current versions of Moq. See this question for how to do it as of at least 4.0.10827

like image 79
kzu Avatar answered Jul 18 '26 05:07

kzu


I figured out how to do this. You can can mock protected methods with Moq, and by making a strict mock, you can verify that they were called. Now I can test the base class without having to make any subclasses.

[Test]
public BaseMethod_should_call_correct_child_method()
{
  //strict mocks will make sure all expectations are met
  var testBaseMock = new Mock<TestBase>(MockBehavior.Strict);

  //expect that ChildMethod1() will be called once. (it's protected)
  testBaseMock.Protected().Expect("ChildMethod1")
    .AtMostOnce();

  var testBase = testBaseMock.Object;

  testBase.runMethod1 = true;
  testBase.BaseMethod();

  //make sure the method was called
  testBase.VerifyAll();
}
like image 37
Lance Fisher Avatar answered Jul 18 '26 05:07

Lance Fisher