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.openRubyの非常に大規模な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')
于 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 に答える