我们在单元测试中使用手写存根,我正在探索在我们的项目中是否需要像 EasyMock 或 Mockito 这样的 Mock 框架。
我没有找到从手写存根切换到 Mocking 框架的令人信服的理由。
任何人都可以回答为什么当他们已经使用手写模拟/存根进行单元测试时会选择模拟框架。
谢谢
我们在单元测试中使用手写存根,我正在探索在我们的项目中是否需要像 EasyMock 或 Mockito 这样的 Mock 框架。
我没有找到从手写存根切换到 Mocking 框架的令人信服的理由。
任何人都可以回答为什么当他们已经使用手写模拟/存根进行单元测试时会选择模拟框架。
谢谢
简单的答案是我们不需要它们。
我们也不需要其他现有的框架,但使用 Mocking 框架让我们的生活更轻松。作为开发人员,我们可以将更多时间花在手头的问题上,而不是创建或执行模拟框架可以做的事情。
“我没有找到从手写存根切换到 Mocking 框架的令人信服的理由。”
我完全一样。我为什么要费心学习一个模拟框架?手写存根做得很好。
我想到了几点,主要是一段时间后,您的测试会因测试存根而变得晦涩难懂。您在使用手写存根时所指的内容称为测试扩展。您扩展代码以启用模拟框架的功能。换句话说,您将代码写入存根,或根据发生的情况返回值。这需要时间和精力。更不用说空间了。一个模拟框架可以在几行代码中完成所有这些工作。
模拟框架的好处是:
当您需要模拟对象时,最大的好处就出现了。必须手写代码来检查一个方法是否被调用、调用了多少次等等,这本身就是一个小任务。如果其他人已经这样做了,并创建了一个经过全面测试、有据可查的框架,那么不使用它是没有意义的。就像任何框架一样,没有它你也可以顺利进行,但有时使用正确的工具会使工作变得容易得多。
您可能想阅读 Martin Fowler 的Mocks Aren't Stubs文章。基本区别是这样的:
有些错误情况无法使用存根进行测试。另一方面,使用模拟的测试通常不太稳定。
虽然可以通过合理的努力手动编写存根,但 Mocks 需要更多的工作。一个好的模拟框架也可以使编写存根更快、更容易。
我以同样的方式开始(手动编写模拟),现在我几乎完全切换到 EasyMock。
我发现使用 EasyMock 通常更快更灵活。
通常,当我第一次需要模拟时,我可以使用 EasyMock 在几行代码中获得它,而我需要手动实现所需的接口(公平地说,这可以由 IntelliJ 之类的 IDE 生成)然后添加必要的代码以产生所需的响应和/或允许感知对其调用的影响。
好吧,有人可能会说,这只是一次性成本。下次我可以愉快地重复使用手写模拟......我发现通常情况并非如此。在另一个测试中,我可能需要一个具有不同行为的同一类的模拟。例如,调用不同的方法,和/或预期不同的结果。一个特定的情况是当 mock 预计会在一个测试用例中抛出异常,但不会在另一个测试用例中抛出异常。好吧,我可以添加一些参数来动态控制行为。然后对于下一个测试,更多的参数来控制更多的行为......所以我最终得到了一个更复杂的模拟实现,这是对更多单元测试的依赖——也带来了无意中破坏旧测试的风险。
与此相反,使用 EasyMock,我可以为每个测试独立配置我的模拟。因此,该行为在单元测试代码本身中是明确控制和可见的,并且没有副作用的风险。
更不用说使用 EasyMock,您可以验证所需的方法是否按所需的顺序调用,如果您需要(我不时这样做)。手动实现这一点(尤其是以通用方式)将非常痛苦,没有额外的好处。
就像其他所有开发人员一样,我发现自己在编写代码而不是使用现有的解决方案——“不是这里发明的”综合症。
您的问题表明您更喜欢编写需要伪造/模拟两次的类,而不是使用可以为您完成此操作的框架。使用模拟框架使您无需在更改伪造对象时编写、重构和更新您的手动模拟。
换句话说,使用模拟框架就像任何其他 3rd 方库(例如 ORM)一样 - 其他人编写了代码,因此您不必这样做。
有时以声明性方式创建模拟可能更容易,它可以帮助您使用框架比手动更轻松地编写某些行为。另一个小优势可能是通过使用模拟框架,您可以明确地模拟模拟。