此处此问题还有其他一些变体,但请阅读整个问题。
通过使用fakes,我们查看构造函数以查看类具有哪种依赖关系,然后相应地为它们创建伪造。
然后我们通过查看它的合同(方法签名)来编写方法的测试。如果我们无法弄清楚如何通过这样做来测试方法,那么我们是否应该尝试重构该方法(最有可能将其分解为更小的部分),而不是查看它内部以确定我们应该如何测试它?换句话说,它也通过这样做为我们提供了质量控制。
嘲笑不是坏事,因为它们要求我们查看我们要测试的方法吗?因此,跳过整个“将签名视为评论家”。
更新以回复评论
然后说一个存根(只是一个提供所请求对象的虚拟类)。
像Moq
这样的框架可确保使用参数Method A
和X
调用Y
。为了能够设置这些检查,需要查看测试方法。
设置所有这些检查时,重要的是(方法合同)是否被遗忘,因为焦点从方法签名/合同转移到方法内部并创建检查。
通过查看合同来尝试测试方法不是更好吗?毕竟,当我们使用该方法时,我们只需在使用它时查看合同。所以它的合同很容易理解,这非常重要。
答案 0 :(得分:3)
这是一个灰色区域,我认为有一些重叠。总的来说,我会说使用模拟对象是我的首选。
我想其中一些取决于你如何测试代码 - 首先测试代码?
如果您遵循带有实现接口的对象的测试驱动设计计划,那么您可以随时生成模拟对象。
每个测试将测试对象/方法视为黑盒子。
它专注于编写更简单的方法代码,因为你知道你想要什么样的答案。
但最重要的是,它允许您拥有使用模拟对象的运行时代码,用于代码的未写区域。
在宏观层面上,它还允许在运行时切换代码的主要区域以使用模拟对象,例如模拟数据访问层,而不是具有实际数据库访问权限的层。
答案 1 :(得分:1)
假货只是愚蠢的虚拟对象。模拟使您能够验证单元的控制流是否正确(例如,它使用预期的参数调用正确的函数)。这样做通常是测试事物的好方法。一个例子是saveProject()
- 函数可能希望在要保存的对象上调用saveToProject()
之类的东西。我认为这比将项目保存到临时缓冲区要好得多,然后加载它以验证一切正常(这比测试更多 - 它还验证saveToProject()
实现是否正确)
从mocks vs stubs开始,我通常(并非总是)发现模拟提供了更清晰的测试和(可选)对期望的更精细控制。模拟可能过于强大,允许您将实现测试到更改测试实现的级别,使结果保持不变,但测试失败。
答案 2 :(得分:1)
通过查看方法/函数签名,您只能测试输出,提供一些输入(只能为您提供所需数据的存根)。虽然在某些情况下这是可以的,但有时你做需要测试该方法中发生的事情,你需要测试行为是否正确。
string readDoc(name, fileManager) { return fileManager.Read(name).ToString() }
你可以在这里直接测试返回值,所以stub工作得很好。
void saveDoc(doc, fileManager) { fileManager.Save(doc) }
在这里你更愿意测试方法Save
是否通过适当的参数调用(doc
)。 doc内容没有改变,fileManager没有输出任何内容。这是因为测试的方法取决于接口提供的一些其他功能。并且,界面是契约,因此您不仅要测试您的方法是否给出正确的结果。您还要测试它是否以正确的方式使用提供的合同。
答案 3 :(得分:0)
我觉得它有点不同。让我解释一下我的观点:
我使用了一个模拟框架。当我尝试测试一个类时,为了确保它能按预期工作,我必须测试可能发生的所有情况。当我的测试类使用其他类时,我必须在某些测试情况下确保使用的类或某个返回值引发特殊异常,等等......这很难用这些类的实际实现来模拟上课,所以我必须写下他们的假货。但我认为在我使用假货的情况下,测试并不那么容易理解。在我的测试中,我使用MOQ-Framework并在我的测试方法中设置了模拟。如果我必须分析我的测试方法,我可以很容易地看到如何配置模拟,并且不必切换到假货的编码来理解测试。
希望能帮助您找到答案......