【问题标题】:Unit testing inheritance hierarchies with Moq使用 Moq 对继承层次结构进行单元测试
【发布时间】:2015-09-18 13:57:44
【问题描述】:

我有一个继承层次结构,如下所示:

public class Foo{
        public virtual IList<string> Messages{get;set;}
}

public class Foo2: Foo{
    public bool DoSomething(){
        //Evaluate something;
    }
}

public class Bar: Foo2{
    public override bool DoSomething(){
        var res = base.DoSomething();
        if(res)
            Messages.Add("Hello World");
        return res;
    }
}

我的测试对象是Bar,测试框架是最小起订量。

        [TestMethod]
        public void TestBar()
        {

            var mockedBar= new Mock<Bar>() {CallBase = true};
            mockedBar.SetupGet(x => x.Messages).Returns(new List<string>());
            mockedBar.Setup(x => x.DoSomething()).Returns(false);

            var result = mockedBar.Object.DoSomething();

            Assert.IsFalse(result, "This should fail");
            mockedBar.Verify(x => x.DoSomething(), Times.Once, "The base DoSomething is called only once.");
         }

我刚刚开始投资于单元测试,但我不确定我是否做得正确。 问题:

  1. 现在正在通过,但我对我的测试方法没有信心。 mockedBar.Setup(x=&gt;x.DoSomething()) 应该设置我的 base.DoSomething() 呼叫。对吗?

  2. 我如何测试 Bar.DoSomething() 实际上填充了 Foo 类中的 Messages

非常感谢任何指导。

【问题讨论】:

  • 模拟要测试的对象是没有意义的。通常,您只模拟要测试的对象的依赖关系。回答你的第一个问题:不,设置没有设置基本方法,而是设置最终对象的方法,它是 Bar 的模拟。
  • 我其实一直在关注这个article
  • 是的,但是那篇文章的作者调用了一种不同于他设置的方法。您正在尝试设置您覆盖且仅调用 base 的方法。

标签: c# unit-testing testing moq


【解决方案1】:

在这种情况下,我认为你不需要mock,只需创建一个Bar对象并正常测试即可。

[TestMethod]
public void TestBar()
{
     var bar = new Bar();
     var result = bar.DoSomething();
     Assert.IsFalse(result, "This should fail");
     //I assume that this is your logic.
     Assert.IsTrue(bar.Messages.Contains("Hello World"));
}

我们只在需要stub or mock外部依赖时创建一个mock。在您的情况下,您没有任何外部依赖项可以模拟。

【讨论】:

  • 我正在测试Bar。那么,FooFoo2 不是外部依赖吗?
  • @Ashish Shakya:我不这么认为。继承是is-a 关系。不是has-a 关系(has an external dependency)。继承的属性成为对象本身的一部分,当FooFoo2 中的任何更改破坏了Bar 中的代码时,单元测试应该检测到这一点。
【解决方案2】:

您正在设置一个模拟,然后使用此代码调用相同的模拟:

mockedBar.Setup(x => x.DoSomething()).Returns(false);
var result = mockedBar.Object.DoSomething();
Assert.IsFalse(result, "This should fail");

所以这实际上并没有调用或测试您的代码。

对于这里的示例,我要么根本不使用模拟,而只测试整个堆栈,要么如果您可以更改正在测试的代码,我会考虑使用依赖注入来删除这种继承。

使用继承来共享代码使测试变得更加困难。

【讨论】:

  • 感谢您确认我的想法。我害怕我根本没有测试任何东西。我也会研究 DI 解决方法。谢谢。
猜你喜欢
  • 2014-10-26
  • 2011-12-24
  • 2016-09-24
  • 2012-06-01
  • 2014-12-22
  • 1970-01-01
  • 2010-09-11
  • 1970-01-01
相关资源
最近更新 更多