【问题标题】:Do mocks break the "test the interface, not the implementation" mantra?模拟是否打破了“测试接口,而不是实现”的口号?
【发布时间】:2013-09-15 04:39:25
【问题描述】:

来自维基百科(强调我的,内部参考已删除):

在“单元测试的艺术”一书中,mock 被描述为一个假对象,通过验证与对象的交互是否发生来帮助确定测试是失败还是通过。

在我看来,模拟正在测试实现。具体来说,他们测试了实现与特定对象交互的方式。

我的解释正确吗?模拟是故意破坏“测试接口,而不是实现”的口头禅吗?或者,是否在单元测试以外的级别进行模拟测试?

【问题讨论】:

    标签: unit-testing testing mocking


    【解决方案1】:

    正确,模拟不遵循“测试接口,而不是实现”的经典口号。模拟使用行为验证而不是状态验证。

    来自http://martinfowler.com/articles/mocksArentStubs.html

    Mocks 使用行为验证。

    因此,Mockist 测试与方法的实现更加耦合。更改调用协作者的性质通常会导致 mockist 测试中断。

    这种耦合导致了几个问题。最重要的是对测试驱动开发的影响。使用 mockist 测试,编写测试会让您考虑行为的实现——事实上,mockist 测试人员认为这是一个优势。然而,古典主义者认为,重要的是只考虑从外部接口发生的事情,并在完成编写测试之后才考虑实现。

    【讨论】:

    • 我本来打算对答案投赞成票,但您似乎回答了自己的问题,就好像它是修辞一样。
    • @bryanbcook 哦。不,只是没有人回答,所以我自己花了更多时间,找到了我认为的答案。我愿意接受反馈(赞成/反对/替代答案)。 stackoverflow.com/help/self-answer
    【解决方案2】:

    在我看来,模拟正在测试实现。 具体来说,他们测试了实现与特定对象交互的方式。

    100% 正确。但是,这仍然是单元测试,只是从不同的角度来看。 假设您有一个方法应该使用某种MathsService 对两个数字执行函数。 MathsService 被分配给 Calculator 类,以便为计算器进行数学运算。

    让我们假设 MathsService 有一个方法,PerformFunction(int x, int y) 应该只是 return x+y

    像这样测试:(以下都是伪代码,为清楚起见,省略了某些位)

    var svc = new MathsService();
    var sut = new Calculator(svc);
    int expected = 3;
    int actual = sut.Calculate(1,2);
    Assert.AreEqual(expected,actual,"Doh!");
    

    这是对单元Calculator.Calculate()黑盒测试。您的测试不知道也不关心答案是如何得出的。这很重要,因为它可以让您对自己的测试正常进行有一定程度的信心。

    但是,请考虑 Calculator.Calculate 的这种实现:

    public int Calculate()
    {
        return 4;
    }
    

    像这样测试:

    var svc = new Mock<IMathsService>(); //did I mention there was an interface? There's an interface...
    svc.Setup(s=>PerformCalculation(1,2)).Returns(3);
    var sut new Calculator(svc.Object);
    sut.Calculate(1,2);
    svc.Verify(s=>PerformCalculation(1,2),Times.Once,"Calculate() didn't invoke PerformFunction");
    

    这个白盒测试并没有告诉您任何关于PerformFunction方法的正确性,但它确实证明了,不管结果如何,Calculator 确实将 x 和 y 传递给了 IAdditionService.PerformCalculation 方法,这就是您希望它执行的操作。

    你当然可以编写其他测试来验证PerformCalculation测试的结果是否在不修改的情况下传回给调用者等。

    有了这些知识,如果你的第一个单元测试现在失败了,你可以满怀信心地直接跳到 MathService 类来查找问题,因为你知道问题可能不是 @987654336 @方法。

    希望对您有所帮助...

    【讨论】:

      猜你喜欢
      • 2010-10-20
      • 1970-01-01
      • 2010-11-24
      • 1970-01-01
      • 2020-06-14
      • 1970-01-01
      • 1970-01-01
      • 2010-09-21
      相关资源
      最近更新 更多