RSpec:在实例化之前,我如何在对象上存根一个方法,而不必存根所有其他方法



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

我使用RSpec3.2和generator_spec来尝试和测试这个功能,但作为一个gem,当它调用generate时,它会抱怨Rails不存在:

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

因此,我一直在尝试存根Generator#generate方法,使其与规范中的run_generator做同样的事情,就在run_generator调用中间调用generate之前。然而,对于我所有潜在的解决方案,我都遇到了问题。

直接重写类-不能使用spec方法

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在幕后调用了一个方法,所以有问题的generator还不存在。

使用实例double不允许使用其他方法

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

然而,使用double需要存根所有将要使用的方法,而其他所有方法只需调用它们的原始实现。这似乎很困难,也没有必要。有什么办法绕过它吗?

Taryn East最终给了我一个重要的线索:我需要在我的测试目录中有一个全面的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

最新更新