我正在为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_spec
的prepare_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