Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Unit testing 在使用模拟对象时,我如何防止我的单元测试需要关于实现内部的知识?_Unit Testing_Oop_Mocking_Dunit_Pascalmock - Fatal编程技术网

Unit testing 在使用模拟对象时,我如何防止我的单元测试需要关于实现内部的知识?

Unit testing 在使用模拟对象时,我如何防止我的单元测试需要关于实现内部的知识?,unit-testing,oop,mocking,dunit,pascalmock,Unit Testing,Oop,Mocking,Dunit,Pascalmock,关于单元测试,特别是关于模拟(我正在使用和框架),我仍处于学习阶段。我现在遇到的一件事是,我找不到一种方法将被测试类/接口的实现细节硬编码到我的单元测试中,这感觉不对 例如:我想测试一个类,该类实现了一个非常简单的接口,用于读取和写入应用程序设置(基本上是名称/值对)。提供给消费者的接口与值实际存储的位置和方式完全无关(例如注册表、INI文件、XML、数据库等)。当然,访问层是由另一个类实现的,该类在构建时被注入到测试类中。我为这个访问层创建了一个模拟对象,现在我能够完全测试接口实现类,而无需实

关于单元测试,特别是关于模拟(我正在使用和框架),我仍处于学习阶段。我现在遇到的一件事是,我找不到一种方法将被测试类/接口的实现细节硬编码到我的单元测试中,这感觉不对

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

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

为了确保模拟在被测试类访问时的行为与真实情况完全相同,我的单元测试必须通过非常明确地定义预期的方法调用和测试类预期的返回值来设置模拟对象

对访问层接口或被测试类使用该层的方式的更改也必须更改单元测试

即使我正在测试的类的接口根本没有改变

“实际测试”?你是说公开的接口类?那很好

“tested”(interface)类使用访问层的方式意味着您已经将内部接口更改为访问层。接口更改(甚至是内部更改)需要进行测试更改,如果您做错了什么,可能会导致中断

这没问题。实际上,整个要点是,对访问层的任何更改都必须对模拟进行更改,以确保更改“有效”

测试不应该是“健壮的”。应该是易碎的。如果你做了改变,改变了内部行为,那么事情就会破裂。如果你的测试太强大,他们不会测试任何东西——他们只会工作。这是错误的

测试只有在正确的理由下才有效

这是我不得不做的事吗 使用mocks时使用,或者存在 一种更好的方法来设计 类依赖关系,以避免 这个

很多时候,mock(特别是像JMock这样敏感的框架)会迫使您考虑与您试图测试的行为没有直接关系的细节,有时这甚至会有帮助,因为它会暴露可疑代码,这些代码做得太多,并且具有太多的调用/依赖项

然而在你的情况下,如果我读对了你的描述,听起来你真的没有问题。如果您正确地设计了读/写层,并且具有适当的抽象级别,那么就不必更改它

这意味着如果我曾经 要更改的接口,请执行以下操作: 访问层或访问方式 被测试的类使用该层I 还必须更换装置 测试内部 即使 类的接口,我实际上是 测试一点也没有改变


编写抽象访问层不是为了避免这种情况吗?一般来说,在之后,这种类型的接口不应该改变,也不应该破坏与使用它的类的契约,并且通过扩展,它也不会破坏您的单元测试。现在,如果您更改了方法调用的顺序,或者必须对抽象层进行新的调用,那么,是的,特别是对于某些框架,您的模拟期望将被打破。这只是使用mock成本的一部分,完全可以接受。但总体而言,接口本身应该保持稳定。

仅为您的示例命名

  • RegistryBasedDictionary实现角色(接口)字典
  • RegistryBasedDictionary依赖于由RegistryWinAPIWrapper实现的角色RegistryAccessor
您目前对测试RegistryBasedDictionary感兴趣。单元测试将为RegistryAccessor角色注入模拟依赖项,并测试与依赖项的预期交互

  • 这里避免不必要的测试维护的诀窍是“精确地指定应该发生什么..而不是更多。”(From(对于模拟风格的TDD必须阅读),因此如果依赖项方法调用的顺序无关紧要,就不要在测试中指定它。这让您可以自由地更改实现中调用的顺序。)
  • 设计角色,使其不包含来自实际实现的任何泄漏-保持角色实现不可知
更改RegistryBasedDictionary测试的唯一原因是更改RegistryBasedDictionary的行为,而不是其任何依赖项。因此,如果其与其依赖项或角色/契约的交互