在测试中使用模拟

not*_*oop 7 c# java testing unit-testing mocking

我刚刚开始在我的测试中使用模拟对象(使用Java的mockito).毋庸置疑,他们简化了测试的设置部分,并且随着依赖注入,我认为它使代码更加健壮.

但是,我发现自己在实施而不是规范的测试中绊倒.我最终建立了期望,我认为这不是测试的一部分.在更多的技术术语中,我将测试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");
Run Code Online (Sandbox Code Playgroud)

那么,在这里我不仅测试attributeWithDefault()遵循的规范,但我还测试了实施,因为我需要它来使用Element.getAttribute(),而不是Element.getAttributeNode().getValue()Element.getAttributes().getNamedItem().getNodeValue()

我认为我会以错误的方式处理它,所以任何关于如何改进我对模拟和最佳实践的使用的提示都将不胜感激.

编辑: 测试有什么问题

我做了上面的假设,测试是一种糟糕的风格,这是我的理由.

  1. 规范没有指定调用哪个方法.例如,只要正确完成,库的客户端就不应该关心如何检索属性.实施者应该有自由的权利,以他认为合适的任何方式访问任何替代方法(关于性能,一致性等).它的规范Element确保所有这些方法返回相同的值.

  2. 重新考虑Element到单个方法接口是没有意义的getElement()(Go实际上很好).为了便于使用,该方法的客户端应该能够只使用Element标准库中的标准.拥有接口和新类只是愚蠢,恕我直言,因为它使客户端代码难看,而且它不值得.

  3. 假设规范保持不变并且测试保持不变,新开发人员可能会决定重构代码以使用不同的使用状态的方法,并导致测试失败!那么,当实际实现符合规范时,测试失败是有效的.

  4. 让协作者以多种格式公开状态是很常见的.规范和测试不应取决于采用哪种特定方法; 只有实施应该!

Yis*_*hai 6

这是模拟测试中的常见问题,一般的咒语就是:

只有您拥有的模拟类型.

在这里,如果你想模拟与XML解析器的协作(不一定需要,老实说,因为一个小的测试XML应该在单元上下文中工作得很好)那么XML解析器应该在你拥有的将要处理的接口或类的后面您需要调用第三方API上哪种方法的混乱细节.重点是它有一个从元素中获取属性的方法.嘲笑那个方法.这将实现与设计分开.真正的实现将有一个真正的单元测试,实际上测试你从真实对象获得一个成功的元素.

模拟可以是一种保存样板设置代码的好方法(基本上用作Stubs),但这不是它们在驱动设计方面的核心目的.模拟测试行为(与状态相反)并且不是Stubs.

我应该补充一点,当你使用Mocks作为存根时,它们看起来就像你的代码.任何存根都必须假设您将如何调用它与您的实现相关联.这很正常.如果这是一个问题,那就是以不良方式推动您的设计.