我仍处于关于单元测试的学习阶段,特别是关于模拟(我正在使用 帕斯卡莫克单位 构架)。我现在偶然发现的一件事是,我找不到一种方法来将测试的类/接口的实现细节硬编码到我的单元测试中,这感觉不对......

例如:我想测试一个类,该类实现一个非常简单的接口,用于读取和写入应用程序设置(基本上是名称/值对)。呈现给消费者的界面完全不知道值的实际存储位置和方式(例如,注册表、INI 文件、XML、数据库等)。当然,访问层是由另一个不同的类实现的,该类在构造时注入到测试的类中。我为此访问层创建了一个模拟对象,现在我可以完全测试接口实现类,而无需实际读取或写入任何注册表/INI 文件/任何内容。

但是,为了确保模拟在被测试类访问时的行为与真实事物完全相同,我的单元测试必须通过非常明确地定义预期的方法调用和被测试类预期的返回值来设置模拟对象。这意味着,如果我必须更改访问层的接口或测试类使用该层的方式,我还必须更改内部使用该接口的类的单元测试,即使 界面 我实际测试的班级根本没有改变。这是我在使用模拟时必须忍受的事情,还是有更好的方法来设计类依赖关系来避免这种情况?

有帮助吗?

解决方案

  

这是不是我就只能   住用嘲笑或有与时   更好的方式来设计   一流的依赖性将避免   此?

很多次模拟考试(特别是像JMock的敏感框架),迫使你帐户的不直接涉及到你要测试的行为细节,有时候这甚至可以通过将可疑代码是有帮助做得太多了,有太多的呼叫/依赖性。

不过你的情况,如果我看了你的描述正确的,这听起来像你真的没有问题。如果你正确使用抽象的适当水平设计的读/写层,你不应该改变它。

  

这意味着,如果我不必   要更改的接口   接入层或所述方式   所测试的类使用层我   还必须改变单位   测试的类在内部   使用该接口,即使   类的接口实际上我   测试已经根本改变。

时不写入该抽象访问层,以避免这点?一般来说,继开/关原则,这种接口的不应的变化,而不是应该打破与该类合同消耗它,并通过扩展它不会破坏你的单元测试,无论是。现在,如果你改变了方法调用的顺序,或者必须做出新的呼叫到抽象层,然后,是的,特别是一些框架,你的模拟期望将打破。这是用嘲笑的成本只是一部分,这是完全可以接受的。但接口本身应,一般地,保持稳定。

其他提示

  

,以确保模拟的行为完全一样,当被测试类来访问,我的单元测试都通过非常明确地定义预期的方法调用和被测试类预期的返回值来设置模拟对象的真实的东西。

正确。

  

改变到接入层的界面或所述方式所测试的类使用层I也将必须改变单元测试

正确。

  

尽管实际上我测试类的接口并没有发生任何变化。

“实际测试”?你指的是裸露的接口类?没关系。

在方式“测试”(接口)类使用接入层装置你已经改变内部接口接入层。界面的变化(甚至内部的)需要测试的变化,可能会导致如果你做错了什么破损。

没有错。实际上,整点是接入层的任何变化的必须需要改变嘲笑以确保变“作品”。

测试是不应该是“稳健”。它应该是易碎的。如果你做出改变,从而变更内部行为,那么事情的可以的突破。如果你的测试过于强大的,他们不考什么 - 他们刚刚工作。这是错误的。

测试应该只针对具体原因权工作。

只是为了给你的例子加上一些名字,

  • RegistryBasedDictionary 实现角色(接口)字典。
  • RegistryBasedDictionary 依赖于由RegistryWinAPIWrapper 实现的角色RegistryAccessor。

您当前有兴趣测试RegistryBasedDictionary。单元测试将为RegistryAccessor Role注入模拟依赖项,并测试与依赖项的预期交互。

  • 避免不必要的测试维护的技巧是“准确指定应该发生什么..就这样了。“ (从 GOOS 书 (必须阅读模拟风格的 TDD),因此如果依赖方法调用的顺序并不重要,则不要在测试中指定它。这使您可以自由更改实现中的调用顺序。)
  • 设计角色,使其不包含实际实现中的任何泄漏 - 保持角色与实现无关.

更改RegistryBasedDictionary 测试的唯一原因是更改RegistryBasedDictionary 的行为,而不是更改其任何依赖项。所以如果它 与其依赖项交互或角色/合同发生变化,测试需要更新. 。这是为了获得独立测试的灵活性而需要付出的基于交互的测试的代价。但实际上,这种情况并不经常发生。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top