使用其他类(作为成员或方法的参数)的类需要具有适合单元测试的实例。如果你有这些类可用并且没有引入其他依赖项,那么使用真实的东西而不是模拟更好吗?
答案 0 :(得分:16)
我说尽可能使用真正的课程。
我非常相信尽可能扩大“单元”测试的界限。在这一点上,它们不是传统意义上的单元测试,而只是一个适用于您的应用程序的自动回归套件。我仍然练习TDD并首先编写我的所有测试,但是我的测试比大多数人的测试要大一些,而我的绿 - 红 - 绿周期需要更长的时间。但是现在我已经这样做了一段时间,我完全相信传统意义上的单元测试并不是他们所能完全解决的。
根据我的经验,编写一些小型单元测试最终会成为未来重构的障碍。如果我有一个使用B的A类,我通过模拟B对其进行单元测试,当我决定将某些功能从A移动到B或反之亦然时,我的所有测试和模拟都必须改变。现在,如果我有测试验证通过系统的端到端流程按预期工作,那么我的测试实际上帮助我确定我的重构可能导致系统外部行为发生变化的地方。
底线是模拟编写特定类的合同,并且最终实际上也指定了一些实现细节。如果你在整个测试套件中广泛使用模拟,你的代码库最终会产生很多额外的惯性,从而抵制任何未来的重构工作。
答案 1 :(得分:4)
只要您对对象有绝对控制权,就可以使用“真实的东西”。例如,如果你有一个只有属性和访问器的对象,你可能没问题。如果要使用的对象中存在逻辑,则可能会遇到问题。
如果类a的单元测试使用类b的实例并且引入b的更改中断b,那么类a的测试也会被破坏。这是您遇到问题的地方,与模拟对象一样,您始终可以返回正确的值。使用“真实的东西”可以进行卷积测试并隐藏真正的问题。
模拟也可能有缺点,我认为有一些模拟和一些你必须找到的真实物体的平衡。
答案 2 :(得分:4)
一个非常好的理由为什么你要使用存根/模拟而不是真正的类。即让你的单元测试(纯单元测试)课程测试隔离等等。这个属性非常有用,保持测试隔离的好处很多:
现在,如果你想在你的测试中使用真正的类,那很好但是不单元测试。您正在进行集成测试,这对于验证需求和整体健全性检查非常有用。集成测试不像单元测试那样经常运行,实际上它主要在提交到最喜欢的代码库之前完成,但同样重要。
您唯一需要考虑的是:
模拟和存根用于单元测试。
真实课程适用于集成/系统测试。
答案 3 :(得分:3)
如果依赖项访问外部系统(如数据库或Web服务),我总是使用依赖项的模拟版本。
如果不是这样,那么它取决于两个对象的复杂性。使用真实依赖性测试被测对象实质上是两组复杂性的乘法。模拟依赖关系让我隔离了被测对象。如果任何一个对象相当简单,那么组合的复杂性仍然可行,我不需要模拟版本。
正如其他人所说,在依赖项上定义一个接口并将其注入到测试对象中会使模拟更容易。
就个人而言,我还没有决定是否值得使用严格的模拟并验证对依赖项的每次调用。我通常这样做,但这主要是习惯。
您可能还会发现这些相关问题很有用:
答案 4 :(得分:2)
仅在首先进行单元测试时使用真实物品。如果它引入了阻止它的依赖关系(循环依赖关系或者如果它首先要求某些其他措施),那么使用'mock'类(通常称为“stub”对象)。
答案 5 :(得分:2)
我对被嘲笑的物品非常谨慎,因为我被他们多次咬过。当你想要隔离的单元测试时它们很棒,但它们有几个问题。主要问题是,如果Order类需要一个OrderItem对象的集合并且您模拟它们,那么几乎不可能验证模拟的OrderItem类的行为是否与实际示例相匹配(通常不会使用适当的签名复制方法)足够)。不止一次,我看到系统失败了,因为模拟的类与真实的类不匹配,并且没有足够的集成测试来捕获边缘情况。
我通常使用动态语言进行编程,而我更喜欢仅覆盖有问题的特定方法。不幸的是,这在静态语言中有时很难做到。这种方法的缺点是你使用集成测试而不是单元测试,有时候很难找到错误。好处是您使用的是实际编写的代码,而不是该代码的模拟版本。
答案 6 :(得分:2)
从我的答案中提取和扩展我如何对继承对象进行单元测试?“> here:
您应该尽可能使用真实对象。
如果真实对象做了一些你不想设置的东西(比如使用套接字,串口,获取用户输入,检索大量数据等),你应该只使用模拟对象。从本质上讲,模拟对象适用于使用真实对象实现和维护测试的估计工作量大于使用模拟对象实现和维护测试的时间。
我不接受“依赖测试失败”的论点。如果一个测试失败,因为依赖的类破坏了,那么测试就完全应该做了。这不是气味!如果依赖的界面发生变化,我想知道!
高度模拟的测试环境是非常高的维护,特别是在接口不断变化的项目的早期阶段。我总是发现尽快开始集成测试更好。
答案 7 :(得分:1)
如果您不关心验证UnitUnderTest应该如何与Thing交互的期望,并且与RealThing的交互没有其他副作用(或者您可以嘲笑这些),那么在我看来完全没问题。让你的UnitUnderTest使用RealThing。
然后,测试覆盖了更多的代码库,这是一个奖励。
我通常发现很容易判断何时应该使用ThingMock而不是RealThing:
答案 8 :(得分:0)
如果你的'真实的东西'只是像JavaBeans这样的价值对象,那就好了。
对于任何更复杂的事情我都会担心,因为模拟框架产生的模拟可以给出关于它们如何被使用的精确期望,例如每次调用的方法数,精确的顺序和预期的参数。你的真实物体无法为你做到这一点,因此你可能会在测试中失去深度。
答案 9 :(得分:0)
如果你根据接口编写代码,那么单元测试就会变得很快乐,因为你可以简单地将任何类的假版本注入你正在测试的类中。
例如,如果您的数据库服务器由于某种原因而关闭,您仍然可以通过编写一个伪数据访问类来进行单元测试,该类包含存储在哈希映射中的某些熟数据或其他东西。
答案 10 :(得分:0)
这取决于您的编码风格,您正在做什么,体验等等。
鉴于这一切,没有什么能阻止你同时使用。
我知道我经常使用术语单元测试。我做的很多事情可能更好地称为集成测试,但更好的是将其视为测试。
所以我建议使用适合的所有测试技术。总体目标是测试好,少时间这样做,并且个人有一种坚实的感觉,这是正确的。
话虽如此,根据您的编程方式,您可能需要考虑使用技术(如接口),这些技术可以使模拟更少受干扰。但是不要在错误的地方使用接口和注入。此外,如果模拟需要相当复杂,可能没有理由使用它。 (你可以在这里的答案中看到很多很好的指导,适合什么时候。)
换句话说:总是没有回答。保持你的智慧,观察什么不起作用以及为什么。