Unit testing 使用mock是一种良好的编程实践还是一种不同的方式?

Unit testing 使用mock是一种良好的编程实践还是一种不同的方式?,unit-testing,agile,mocking,Unit Testing,Agile,Mocking,你们会说使用mock比不使用mock好吗? 模拟是仅在单元测试中使用,还是可以作为真实对象直接在原始项目中使用并在之后切换 我到处都在读,我发现模拟最吸引人的地方是层隔离。模拟在单元测试中绝对有用。当您想单独测试依赖于B的A时,您可以模拟B(使用预期的输入/输出)来测试A。您可以确保单独测试B以确保它是正确的 在动态语言中,它们不是严格必需的。但是模拟框架可以帮助您验证您在模拟上设定的期望是否得到满足 您永远不应该使用模拟作为真正的实现。那种事是开玩笑的事。“我们可以模拟整个应用程序!啊啊!”这

你们会说使用mock比不使用mock好吗? 模拟是仅在单元测试中使用,还是可以作为真实对象直接在原始项目中使用并在之后切换


我到处都在读,我发现模拟最吸引人的地方是层隔离。

模拟在单元测试中绝对有用。当您想单独测试依赖于B的A时,您可以模拟B(使用预期的输入/输出)来测试A。您可以确保单独测试B以确保它是正确的

在动态语言中,它们不是严格必需的。但是模拟框架可以帮助您验证您在模拟上设定的期望是否得到满足


您永远不应该使用模拟作为真正的实现。那种事是开玩笑的事。“我们可以模拟整个应用程序!啊啊!”这就是接口/等价物的用途……

最终,可以说这是“另一种方式”。软件已经编写了几十年,并且继续在没有模拟的情况下编写

它主要是一个单元测试工具

模拟/存根真正起作用的是测试驱动的开发。在没有模拟/存根的情况下,人们面临的问题是,应用程序中的依赖关系网通常是这样的,在编写测试之前,您必须构建几乎整个应用程序,甚至在测试更大的功能部分时,隔离bug变得更加困难

考虑以下几点:

  • 我想创建
    ClassA
    ,并编写测试来验证其行为
  • 我开始编写测试(首先进行测试以完成设计)
  • 哎呀,
    ClassA
    需要从
    RepositoryM
    获取数据
  • 我将实现
    RepositoryM
    ,以便测试
    ClassA
  • 哦,但是首先让我们为
    RepositoryM
    编写测试
  • 糟糕,
    RepositoryM
    确实需要
    ServiceX
    来填充其数据
  • 我将实现
    ServiceX
    ,这样我就可以测试并实现
    RepositoryM
    ,这样我就可以测试并实现
    ClassA
……等等

使用mock允许您开始编写测试,而无需实现任何功能。您所需要的只是接口

使用模拟框架可以大大加快测试构建速度

mock/stubing有一些附带的好处——其中之一是将编程强制到抽象而不是实现

你们会说使用 mock比不使用mock好吗

驾驶摩托车比开车好吗?这取决于您试图实现的目标:)

为什么要使用模拟?

模拟与基于状态的测试:虽然我通常喜欢基于状态的测试,因为它感觉更可靠/直接,但通常情况下,使用模拟是验证代码单元正确执行其角色的唯一方法。为什么?好的,在设计时牢记,类通常不会公开足够的数据来验证您的期望,所以验证它是否正常工作的唯一方法是检查它的行为/与其他协作者的交互

一个很好的例子是一个在订单完成时发送电子邮件的类——该类没有“number of emails sent”属性或任何类似属性,因此您需要检查是否进行了适当的方法调用。模拟设定了对交互的期望

虽然您可以通过手动滚动您自己的测试双类来测试交互,该类公开此数据(例如,创建实现所需接口的类型,然后将方法调用信息推送到列表中,然后针对存储状态断言),模拟框架通过允许我们只填充我们真正关心的部分来加速这个过程

我应该在生产代码中使用模拟吗?

模拟是只在单元测试中使用还是可以 在原项目中直接作为真实项目使用 对象,然后切换它

如果“mocking”指的是使用“一种可以被交换并以合理方式运行的‘假’类型”,那么是的——我经常使用‘假’类型,例如内存中的字典来代替数据库连接等等。它们可以在非实时生产代码中充当有用的权宜之计

类似地,如果编程到接口,则可以创建具有存根功能的应用程序的工作框架。这有助于充实完整的编程结构,而不必关注细节。一旦真正的实现可用,您就可以在其中进行替换(尽管如果没有集成测试的支持,可能会出现一些集成错误)


另一方面,如果“mocking”的意思是“在生产代码中使用mocking框架”,那么不——我不建议这样做,我会手工编写假实现,并且不受依赖性的影响,另外,它更易于推理和调试。

模拟的另一个方便之处是,它们的设置速度通常比真实的要快得多(特别是如果说,真实的东西是数据库绑定的),这使得运行测试的速度要快得多。当你说我不应该使用模拟作为真实的实现时,你的意思是我应该只在我想要测试的真实对象之外使用模拟,或者只是我不应该将模拟作为最终产品使用——这显然不是一个好主意。假设我在类a中有一个实方法,它应该调用类B中的实方法,可以在实类a中模拟类B,或者我应该在testclass中测试它并设置实类a和模拟类B@arturo您只能在单元测试的上下文中进行模拟。+1!尽管你可以在开发过程中使用模拟或伪造来允许你在web服务或其他依赖项未完成时演示或UI测试你的应用程序;你不需要