我刚开始在我的测试中使用模拟对象(使用Java的mockito)。不用说,他们简化了测试的设置部分,并且与依赖注入一起,我认为它使代码更加健壮。Mocks在测试中的使用
但是,我发现自己在测试实施而不是规格测试中绊倒。我最终设定了期望,我会认为它不是测试的一部分。用更专业的术语来说,我将测试SUT(被测试的类)和它的合作者之间的交互,而这种依赖不是合同的一部分或者类的接口!
请考虑您拥有以下内容: 处理XML节点时,假设您有一个方法attributeWithDefault()
,它返回节点的属性值(如果可用),否则将返回默认值!
我会设置的测试类似如下:
Element e = mock(Element.class);
when(e.getAttribute("attribute")).thenReturn("what");
when(e.getAttribute("other")).thenReturn(null);
assertEquals(attributeWithDefault(e, "attribute", "default"), "what");
assertEquals(attributeWithDefault(e, "other", "default"), "default");
嗯,这里我不仅测试attributeWithDefault()
坚持的规范,但我还测试了实施,因为我需要它使用Element.getAttribute()
,而不是Element.getAttributeNode().getValue()
或Element.getAttributes().getNamedItem().getNodeValue()
等
我认为我是以错误的方式去解决这个问题,所以有关如何改进我对模拟和最佳实践的使用的任何提示将不胜感激。
编辑: 有什么不对的测试
我做上面的测试是不良作风的假设,这里是我的理由。
该规范没有指定调用哪个方法。例如,图书馆的客户不应该关心如何检索属性,只要它是正确的。实施者应该有自由的统治权利以任何他认为合适的方式(关于性能,一致性等)访问任何替代方法。这是
Element
的规范,确保所有这些方法返回相同的值。将
Element
重新分解为单个方法接口getElement()
(实际上Go非常好),没有任何意义。为了便于使用,该方法的客户应该能够仅使用标准库中的标准Element
。拥有接口和新类只是简单的傻瓜,恕我直言,因为它使客户端代码丑陋,这是不值得的。假设规范保持原样并且测试保持不变,新开发人员可能决定重构代码以使用不同的方法来使用状态,并导致测试失败!那么,当实际实现符合规范时,测试失败是有效的。
使协作者以多种格式公开状态是很常见的。规范和测试不应取决于采取哪种特定方法;只有实施应该!
+1。就像你如何澄清行为(模拟)与状态(存根)测试之间的区别。 – notnoop 2009-11-19 18:18:22