Moq断言一个抽象方法被调用

时间:2013-03-20 17:56:49

标签: c# unit-testing moq autofixture

我正在使用AutoFixture为Abstract类编写单元测试,这是我正在尝试做的事情的代表:

public abstract class Base
{
    public virtual void DoSomethingCool()
    {
        OnDoingSomethingCool();
    }

    protected abstract void OnDoingSomethingCool();
}

我的单元测试看起来像这样:

[TestMethod]
public void TestMethod1()
{
    var fixture = new Fixture().Customize(new AutoMoqCustomization());

    var sut = fixture.Create<Base>();

    // How to assert that the OnDoingSomethingCool method was called
    sut.Invoking(x => x.DoSomethingCool())
        .ShouldNotThrow();
}

那么如何断言受保护的抽象方法实际上是在DoSomethingCool方法中调用的?

如果它是来自注入依赖项的对象,我将能够使用Moq设置模拟并断言该方法被调用,但由于该方法是一个抽象方法在我的主题下测试,如何断言该方法被调用?

1 个答案:

答案 0 :(得分:6)

有一堆可以说的:

  1. 看起来你可能要么测试太多,要么对其他实现提供太多控制。

    • (控制太多)通常,如果您想强制从abstract class中的其他方法调用方法,则不要使其public virtual。通过这样做,您已经为将来的实现提供了更改此行为的能力。事实上,如果您删除virtual,那么您可以获得所需的测试(见下文)。我确实提供了保持virtual的方法,但是再次......不推荐。不建议这样做,因为你的SUT是你的模拟......感觉不对。
    • (测试太多)您应该只关心基本行为,而不是实现细节,以免您的测试变得太脆弱。我假设不仅仅调用OnDoingSomethingCool方法,否则你应该把它作为主要方法。如果主要行为是此次调用(并且不仅仅是此次调用),那么我会在下面的NotRecommended方法中介绍此内容。
  2. 您不应直接测试抽象类。您应该使用Roy Osherove在The Art of Unit Testing中称为抽象测试类模式的内容。这使得所有实现都可以测试您的行为。然后,您可以传递依赖项。如果你想要那个例子,甚至是抽象测试类模式的简化例子,请告诉我

  3. /

    using Moq.Protected;
    
    ...
    
    public void NotRecommended_ProbablyTestingTooMuch_BrittleTestBelow
    {
        //If you MUST keep DoSomethingCool virtual
        //var baseMock = new Mock<Base>{CallBase = true};
        var baseMock = new Mock<Base>();
        baseMock.Protected().Setup("OnDoingSomethingCool");
    
        baseMock.Object.DoSomethingCool();
    
        baseMock.Protected().Verify("OnDoingSomethingCool", Times.AtLeastOnce());
    }