How do I stub a file.read call so that it returns what I want it to? The following does not work:
def write_something
File.open('file.txt') do |f|
return contents = f.read
end
end
# rspec
describe 'stub .read' do
it 'should work' do
File.stub(:read) { 'stubbed read' }
write_something.should == 'stubbed read'
end
end
It looks like the stub is being applied to the File
class and not the file instance inside my block. So File.read
returns stubbed read
as expected. But when I run my spec it fails.
I should note that File.open
is just one part of Ruby’s very large I/O API, and so your test is likely to be very strongly coupled to your implementation, and unlikely to survive much refactoring. Further, one must be careful with “global” mocking (i.e. of a constant or all instances) as it can unintentionally mock usages elsewhere, causing confusing errors and failures.
Instead of mocking, consider either creating an actual file on disk (using Tempfile
) or using a broader I/O mocking library (e.g. FakeFS).
If you still wish to use mocking you can somewhat safely stub File.open
to yield a double (and only when called with the correct argument):
file = instance_double(File, read: 'stubbed read')
allow(File).to receive(:open).and_call_original
allow(File).to receive(:open).with('file.txt') { |&block| block.call(file) }
or, somewhat dangerously, stub all instances:
allow_any_instance_of(File).to receive(:read).and_return('stubbed read')
The main point is to make File.open
to return an object that will respond to read
with the content you want, here's the code:
it "how to mock ruby File.open with rspec 3.4" do
filename = 'somefile.txt'
content = "this would be the content of the file"
# this is how to mock File.open:
allow(File).to receive(:open).with(filename, 'r').and_yield( StringIO.new(content) )
# you can have more then one of this allow
# simple test to see that StringIO responds to read()
expect(StringIO.new(content).read).to eq(content)
result = ""
File.open('somefile.txt', 'r') { |f| result = f.read }
expect(result).to eq(content)
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With