为什么要使用Mocks和Stub来测试Rails应用程序?

时间:2018-04-12 14:39:32

标签: ruby-on-rails ruby unit-testing rspec

我不是要求测试双打(模拟)和接收(存根)的定义。我得到了来自SO的那些plenty。我根本不知道测试中为什么需要测试。从我正在审查的Rspec示例中,程序员使用了这个:

it "allows setting responses" do
  dbl = double("Chant")
  allow(dbl).to receive(:hey!) { "Ho!" }
  expect(dbl.hey!).to eq("Ho!")
end

无论我们运行这个具体例子多少次,它都会一直通过。它永远不会失败。测试的目的是确定示例是通过还是失败。那么为什么即使有一个双倍,如果它总是会通过?

3 个答案:

答案 0 :(得分:4)

当您的测试符合您的应用程序或被测对象的边界时,可以使用模拟和存根。

例如,如果您正在测试对B具有依赖性的对象A,则如果B的行为不相关或者设置B的成本很高,则可以选择存根B.

它们也可用于强制执行决定论。例如:

class DiceRoll
  attr_accessor :value

  def initialize
     @value = (1..6).to_a.sample
  end
end

在这里,我们可能会选择删除dice_roll.value,以便我们可以确定地指定在使用它的类中应该发生什么。一个常见的例子是测试HTTP客户端中的网络故障,除非你真的快速拔掉插头,否则很难实现。

Stubs可用于对ENV vars进行配置,以根据外部因素测试组件的行为。

它们还可用于删除外部协作者(如API,数据库甚至文件系统)的依赖关系。

一个常用的例子是FactoryBot.build_stubbed,它创建一个模型实例,其行为就像它在没有实际接触数据库的情况下被保留一样。

为了它而存在抄写或嘲弄没有固有的价值。它们是可用于解决棘手情况或提高性能的工具。应始终将模拟与测试敏锐度进行权衡 - 这是您的测试实际测试应用程序的程度。

答案 1 :(得分:2)

这个测试确实不是很有用。但想象一下,您正在测试,例如,导出生成功能。要构建导出文件,您需要调用外部服务(如数据库或API)。出于测试生成内容的正确性的目的,您可以假设该服务按预期工作并返回已知良好的格式良好的响应。那就是你存根/嘲笑的地方。

答案 2 :(得分:0)

在Rails的上下文中,存根/模拟在努力遵循合理的test pyramid方面是非常宝贵的。

以Rails控制器测试为例。

Rails控制器:

  1. 接收请求正文
  2. (理想情况下)将与处理请求相关的繁重任务委托给其他对象
  3. 回复请求
  4. 单元测试控制器将涉及通过测试记录控制器对各种请求主体的响应 - 所有人都应关心的是请求,控制器操作的响应和执行的对象的返回值步骤2.中的繁重工作,可以通过在步骤2.中模拟对象或通过对某些方法调用的响应进行存根来轻松实现。 (作为先决条件,我会确保执行重物的物体在控制器测试中嘲笑之前进行了自己的单元测试。)

    根据您的应用程序,您可能还决定不使用模拟编写控制器测试,而是编写集成测试以测试对象。这有时是理想的方法,特别是当工人物体本身很轻时。在一天结束时,我会尽量确保我不会反转测试金字塔,尽管可能会有这样做的情况。

    在模型/服务对象测试中,个人而言,如果操作昂贵且冗余,我也不想与数据库进行交互。

    模拟的优势在集成测试中很明显,特别是在基于微服务的体系结构中,您的应用程序必须做的是通过网络进行通信,而不关心其他服务如何处理请求。能够存储其他服务的响应非常重要。