Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.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_Tdd_Mocking - Fatal编程技术网

Unit testing 如何避免从模拟对象列表返回模拟

Unit testing 如何避免从模拟对象列表返回模拟,unit-testing,tdd,mocking,Unit Testing,Tdd,Mocking,我正在尝试模拟/责任驱动的设计。对于需要服务来检索其他对象的对象,我似乎很难避免从mock返回mock 例如,一个对象可以检查上个月的账单是否已支付。它需要一个检索账单列表的服务。所以我需要在测试中模拟billRetrievalService。同时,我需要BillRetrievalMock返回模拟的账单(因为我不希望我的测试依赖于账单实现的正确性) 我的设计有缺陷吗?有没有更好的方法来测试这一点?或者这是使用finder对象时需要的方式(在本例中是查找账单) 旁注:尽管Bill可能是一个值对象候

我正在尝试模拟/责任驱动的设计。对于需要服务来检索其他对象的对象,我似乎很难避免从mock返回mock

例如,一个对象可以检查上个月的账单是否已支付。它需要一个检索账单列表的服务。所以我需要在测试中模拟billRetrievalService。同时,我需要BillRetrievalMock返回模拟的账单(因为我不希望我的测试依赖于账单实现的正确性)

我的设计有缺陷吗?有没有更好的方法来测试这一点?或者这是使用finder对象时需要的方式(在本例中是查找账单)


旁注:尽管Bill可能是一个值对象候选者,但当集合不包含值对象(例如用户)时,更广泛的问题仍然存在。

模拟返回模拟是一种强烈的代码气味-设计中可能存在的问题。可能是账单应该是不可变的值对象,不应该被模仿。或者,课程的设计和职责有些混乱


模拟物体发明者的书和论文值得一读。

通常,当我模拟物体时,我会得到一堆物体。第一个对象是协调器
BillsPaidLastMonthCoordinator
此对象有两个依赖项
BillRetrievalService
BillPaidValidator

您将模拟这两个依赖项,并且您的测试将用于检索和向验证传递账单的交互。因此,对于本测试,您将不关心数据是什么。这有助于分离责任。您的原始对象负责检索
账单
,然后查看它是否是isPaid账单

按照您描述问题的方式,您最终可能会遇到一个嘈杂而脆弱的测试。脆性来自于它能以两种方式被打破

使用corrdinator,如果
Bill
实现发生更改,则不必更改,只需更改实际使用
Bill
的对象即可。我的25岁生日

[编辑]

这与使用事件处理程序(协调器)更为一致,作为建议,任何原则,无论多么好,都不应该被绝对接受,因此这也符合您不应该需要模拟返回模拟的规则,在某些情况下这是非常合适的


正如Gutzofter所建议的,您可以将对象分成两部分,一部分用于实际验证,另一部分用于检索要验证的账单。这种“单一责任”原则应用程序的优点是验证器更加通用和可重用。另一方面,如果您只有这个简单的用例,并且对更高的可重用性没有特殊需求,那么将检索和验证保持在单个类中是非常实用的。仅仅为了满足抽象的原则而进行的分层、对象数量的爆炸等不符合实际需要和实际利益的行为是不好的。你总是要权衡利弊,现实很少像我们所希望的那样简单和美丽:-)Adam Bien的现实世界Java EE模式中就是这种务实方法的好例子-反思最佳实践。

大多数时候,如果我需要一个模拟来返回另一个模拟,我发现在另一个方向上,依赖性更有意义。换句话说,mock返回mock通常表示违反了依赖倒置原则

一个常见的例外:创建对象的工厂(与每次只返回相同对象的“持有者”相反)。如果在我的生命周期中需要创建多个相同类型的对象,那么我可能需要依赖
ObjectFactory
并调用
#createObject()
,然后可能需要设置对象的期望值。即便如此,我还是会质疑这一点。调用堆栈上一级的其他东西可能会为我创建
对象
s,并根据需要将它们提供给我

ObjectHolder
的情况下,我宁愿直接依赖
对象
,并强制调用方根据需要将其提供给我,而不是依赖
ObjectHolder
来获取
对象。这尊重了上下文独立的理想设计特性


这个问题的一个具体版本是“虚拟时钟”模式。有时您需要依赖于虚拟时钟,但通常只需要一个时间戳(“瞬时请求”模式)或者,最坏的情况下,一个时间戳流,不管它来自何处,都会更好。测试可以提供一个方便的、硬编码的时间戳控制流,但也可以很容易地将系统时钟转换为时间戳流。

请注意,最后一个标记太长,因此被截断(并且有一个拼写错误)。您是返回模拟账单,还是只返回存根?一个返回存根列表的服务对我来说似乎是完全可以接受的。@Mathias那些是mock我的对象需要一个(mock)方法的结果。我拥有一本书,并且已经读过这篇论文。我想避免的是失败的测试,我想知道失败来自于账单中的isPaid逻辑。当值对象非常简单时,不模仿它们似乎是合理的。