8

如何存根 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但是当我运行我的规范时它失败了。

4

3 回答 3

13

我应该注意到这File.open只是 Ruby 非常大的 I/O API 的一部分,因此您的测试很可能与您的实现紧密耦合,并且不太可能在大量重构中幸存下来。此外,必须小心“全局”模拟(即常量或所有实例),因为它可能会无意中模拟其他地方的用法,从而导致令人困惑的错误和失败。

与其模拟,不如考虑在磁盘上创建一个实际文件(使用Tempfile)或使用更广泛的 I/O 模拟库(例如FakeFS)。

如果您仍然希望使用模拟,您可以稍微安全地存根File.open以产生双精度(并且仅在使用正确参数调用时):

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')
于 2012-09-10T01:29:20.457 回答
1

重点是要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
于 2015-11-26T21:17:20.227 回答
0

我就是这样做的

    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  
于 2018-01-12T16:01:28.267 回答