如何存根file.read调用以便它返回我想要的内容?以下不起作用:
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
看起来这个存根被应用于File
类而不是我块中的文件实例。所以File.read
按预期返回stubbed read
。但是当我运行我的规范时,它失败了。
我应该注意到File.open
只是Ruby非常大的I / O API的一部分,所以你的测试可能非常强烈地与你的实现相结合,并且不太可能在重构过程中存活下来。此外,必须小心“全局”模拟(即常量或所有实例),因为它可能无意中模仿其他地方的用法,导致混乱的错误和失败。
而不是模拟,考虑在磁盘上创建实际文件(使用Tempfile
)或使用更广泛的I / O模拟库(例如FakeFS)。
如果您仍然希望使用模拟,您可以在某种程度上安全地将File.open
存根以产生一个double(并且只有在使用正确的参数调用时):
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) }
或者,有点危险,存根所有实例:
allow_any_instance_of(File).to receive(:read).and_return('stubbed read')
主要的一点是让File.open
返回一个对象,它会响应你想要的内容read
,这里是代码:
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
我就是这样做的
describe 'write_something' do
it 'should work' do
file_double = instance_double('File')
expect(File).to receive(:open).with('file.txt').and_yield(file_double)
expect(file_double).to receive(:read).and_return('file content')
content = write_something
expect(content).to eq('file content')
end
end