使用Moq调用验证受保护的抽象方法

时间:2008-12-24 02:14:47

标签: unit-testing testing moq

假设我有以下课程:

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

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

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

我也有班级

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

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

}

我正在使用Moq,我想编写一个测试来验证当我调用BaseMethod()并且runMethod1为true时调用ChildMethod1()。是否可以使用Moq创建TestBase的实现,调用BaseMethod()并验证是否在Moq实现上调用了ChildMethod?

[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

}

4 个答案:

答案 0 :(得分:5)

您还可以将期望/设置设置为可验证,并且不需要严格模拟:

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

  ...

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

修改 此语法在当前版本的Moq中不起作用。有关如何执行此操作,请参阅this question至少4.0.10827

答案 1 :(得分:4)

我想出了如何做到这一点。您可以使用Moq模拟受保护的方法,并通过严格模拟,您可以验证它们是否被调用。现在我可以测试基类而不必创建任何子类。

[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();
}

答案 2 :(得分:1)

这有点像黑客,但如何创建一个使ChildMethod1和ChildMethod公开然后Moqing的TestBase的子类呢?

答案 3 :(得分:0)

看起来您正在测试行为而不是公共接口。如果是这样的话,你可能会看一下测试私人成员的建议。

“是否可以使用Moq创建TestBase的实现,调用BaseMethod()并验证是否在Moq实现上调用了ChildMethod?”

这有点可能。但是你会测试模拟对象,而不是真实对象。

两个可能引导你朝着正确方向前进的问题:

  1. descendatn类是否返回与基类不同的值?如果是这样,你可以测试它并忽略implimentation细节(使重构更容易)。

  2. 后代类是否调用不同的方法或不同的依赖项?如果是这样,您可以检查依赖项。