I have a Ruby cli program that can optionally load a user-specified file via require
. I would like to unit test this functionality via RSpec. The obvious thing to do is to mock the require and verify that it happened. Something like this:
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
(That's just typed, not copy/pasted - the actual code would obscure the question.)
No matter what I try, I can't capture the require
, even though it's occurring (it raises a LoadError
, so I can see that). I've tried a variety of things, including the most obvious:
expect(Kernel).to receive(:require).with(file).and_return(true)
or even:
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)
but nothing seems to hook onto the require
Suggestions?
So require
is defined by Kernel
but Kernel
is included in Object
so when you call require
inside this context it is not necessarily the Kernel
module that is processing the statement.
Update
I am not sure if this exactly solves your issue but it does not suffer from the strange behavior exhibited below:
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)
OLD Answer:
This is incorrect and exists only for posterity due to the up-votes received. Some how works without the allow
. Would love it if someone could explain why as I assumed it should raise instead. I believe the issue to be related to and_return
where this is not part of the expectation. My guess is we are only testing that self received require
, with_file
, and that the and_return
portion is just a message transmission (thus my updated answer)
You can still stub this like so:
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
Since I am unclear on your exact implementation since you have obfuscated it for the question I cannot solve your exact issue.