RSpec:如何在实例化之前对对象的方法进行存根,而不必存根所有其余部分?

RSpec: How can I stub a method on an object, before instantiation, without having to stub all the rest?

我正在为 Rails 编写 gem,其中包括用于创建模型的生成器。在某些情况下,生成器应该调用自己,它使用 generate 方法来执行此操作。实际使用时效果很好

我正在使用 RSpec 3.2 和 generator_spec 来尝试测试此功能,但是作为 gem,当它到达 generate 调用时,它会抱怨Rails 不存在:

/path/to/ruby: No such file or directory -- bin/rails (LoadError)

所以我一直在尝试对 Generator#generate 方法进行存根处理,使其与规范中的 run_generator 做同样的事情,紧接在调用 [=15] 的 run_generator 调用之前=] 在他们中间。 但是,对于我所有可能的解决方案,我遇到了 运行 个问题。

完全覆盖 class - 无法使用规范方法。

class Generator
  def generate(*args)
    run_generator args[1..-1]
  end
end

这会引发 undefined method 'run_generator'。不足为奇。

使用部分双精度 - 实例化太迟。

allow(generator).to receive(:generate) { |*args| run_generator args[1..-1] }

这将是完美的,但是 run_generator 在幕后调用了一个 class 方法,所以有问题的 generator 不会还存在。

使用双实例 - 不允许使用其他方法。

recursible = instance_double(Generator)
allow(recursible).to receive(:generate) { |*args| run_generator args[1..-1] }
test_case_instance.generator_class = recursible

但是,使用 double 需要您存根 所有 上面将要使用的方法 - 其余所有方法都将简单地调用它们的原始实现。这似乎很困难而且没有必要。有什么办法绕过它吗?

Taryn East ended up giving me the :我的测试目录中需要一个成熟的 Rails 应用程序。

不幸的是,generator_specprepare_destination 方法完全破坏了目标目录,所以这就是我最后的结果:

it 'the test' do
  system "rails new #{destination_root} -Bfq" # no bundling, force overwrite, quiet
  File.write "#{destination_root}/Gemfile", "gem '#{File.basename Dir.pwd}', path: '#{Dir.pwd}'", mode: 'a'
  system "cd #{destination_root} && bundle install --quiet"

  # ... continue with the test as before