单元测试以验证是否调用了基类方法

时间:2016-04-19 18:35:40

标签: c# unit-testing moq

我有一个基类:

public abstract class MyBaseClass
{
    protected virtual void Method1()
    {    
    }
} 

和派生类:

public class MyDerivedClass : MyBaseClass
{
    public void Method2()
    {
        base.Method1();
    }
}

我想为Method2编写单元测试,以验证它是否在基类上调用Method1。我正在使用Moq作为我的模拟库。这可能吗?

我遇到了一个相关的SO链接:

Mocking a base class method call with Moq

其中第二个答案表明可以通过在模拟对象上将CallBase属性设置为true来实现。但是,目前尚不清楚如何验证对基类方法(上例中的Method1)的调用。

对此表示感谢。

3 个答案:

答案 0 :(得分:11)

单元测试应该验证行为,而不是实现。这有几个原因:

  • 结果是目标,而不是 结果
  • 的方式
  • 测试结果可让您改进实施,而无需重新编写测试
  • 实施更难模仿

可能能够放入钩子或创建验证基本方法被调用的模拟,但你真的关心如何实现答案,或者做你关心的答案正确

如果您需要的特定实施具有可以验证的副作用,那么 就是您应该验证的。

答案 1 :(得分:4)

从派生类的角度模拟基类是不可能的。在您的简单示例中,我建议使用两个选项之一。

选项1:如果MyDerivedClass确实不应该关注MyBaseClass的内容,那么请使用依赖注入! Yay抽象!

public class MyClass
{
    private readonly IUsedToBeBaseClass myDependency;

    public MyClass(IUsedToBeBaseClass myDependency){
        _myDependency = myDependency;
    }

    public void Method2()
    {
        _myDependency.Method1();
    }
}

在测试土地的其他地方......

[TestClass]
public class TestMyDependency {
    [TestMethod]
    public void TestThatMyDependencyIsCalled() {
        var dependency = new Mock<IUsedToBeBaseClass>();
        var unitUnderTest = new MyClass(dependency.Object);
        var unitUnderTest.Method2();
        dependency.Verify(x => x.Method1(), Times.Once);
    }
}

选项2:如果MyDerivedClass需要了解MyBaseClass正在做什么,那么测试MyBaseClass正在做正确的事情

在替代试验场......

[TestClass]
public class TestMyDependency {
    [TestMethod]
    public void TestThatMyDependencyIsCalled() {
        var unitUnderTest = new MyDerivedClass();
        var unitUnderTest.Method2();
        /* verify base class behavior #1 inside Method1() */
        /* verify base class behavior #2 inside Method1() */
        /* ... */
    }
}

答案 2 :(得分:1)

您所描述的不是对您的代码的测试,而是对该语言行为的测试。这没关系,因为这是确保语言按照我们认为的方式行事的好方法。在我学习的时候,我曾经写过很多小的控制台应用程序。我希望我对单元测试有所了解,因为这是一个更好的方法。

但是,一旦您对其进行了测试并确认语言的行为符合您的预期,我就不会继续为此进行测试。您只需测试代码的行为即可。

这是一个非常简单的例子:

public class TheBaseClass
{
    public readonly List<string> Output = new List<string>();

    public virtual void WriteToOutput()
    {
        Output.Add("TheBaseClass");
    }
}

public class TheDerivedClass : TheBaseClass
{
    public override void WriteToOutput()
    {
        Output.Add("TheDerivedClass");
        base.WriteToOutput();
    }
}

单元测试

    [TestMethod]
    public void EnsureDerivedClassCallsBaseClass()
    {
        var testSubject = new TheDerivedClass();
        testSubject.WriteToOutput();
        Assert.IsTrue(testSubject.Output.Contains("TheBaseClass"));
    }