如何在 RSpec 中模拟 Ruby "require" 语句?

How can I mock a Ruby "require" statement in RSpec?

我有一个 Ruby cli 程序,可以选择通过 require 加载用户指定的文件。我想通过 RSpec 对这个功能进行单元测试。显而易见的事情是模拟需求并验证它是否发生。像这样:

context 'with the --require option' do
  let(:file) { "test_require.rb" }
  let(:args) { ["--require", "#{file}"] }
  it "loads the specified file"
    expect(...something...).to receive(:require).with(file).and_return(true)
    command.start(args)
  end
end

(这只是输入,而不是 copy/pasted - 实际代码会掩盖问题。)

无论我尝试什么,我都无法捕获 require,即使它正在发生(它引发 LoadError,所以我可以看到)。我尝试了多种方法,包括最明显的方法:

expect(Kernel).to receive(:require).with(file).and_return(true)

甚至:

let(:kernel_class) { class_double('Kernel') }
kernel_class.as_stubbed_const
allow(Kernel).to receive(:require).and_call_original
allow(Kernel).to receive(:require).with(file).and_return(true)

但似乎没有任何内容挂钩到 require

建议?

因此 requireKernel 定义,但 Kernel 包含在 Object 中,因此当您在此上下文中调用 require 时,它不一定是Kernel 正在处理语句的模块。

更新

我不确定这是否能完全解决您的问题,但它不会出现以下奇怪的行为:

file = 'non-existent-file'
allow(self).to receive(:require).with(file).and_return(true)
expect(self).to receive(:require).with(file)
expect(require file).to eq(true)

Working Example

旧答案:

这是不正确的,由于 up-votes 收到,仅供后代使用。一些没有 allow 的工作方式。如果有人能解释为什么我认为它应该提高,我会很高兴。我认为这个问题与 and_return 有关,这不是预期的一部分。我的猜测是我们只测试自己收到 requirewith_file,而 and_return 部分只是消息传输(因此我更新了答案)

你仍然可以像这样存根:

file = 'non-existent-file.rb'
allow_any_instance_of(Kernel).to receive(:require).with(file).and_return(true)
expect(self).to receive(:require).with(file).and_return(true)
require file

由于我不清楚你的具体实现,因为你对问题进行了混淆处理,我无法解决你的确切问题。