RSpec: how to test file operations and file content

后端 未结 5 741
心在旅途
心在旅途 2020-12-24 00:40

In my app, I have the following code:

File.open "filename", "w" do |file|
  file.write("text")
end

I want to te

相关标签:
5条回答
  • 2020-12-24 01:19

    For very simple i/o, you can just mock File. So, given:

    def foo
      File.open "filename", "w" do |file|
        file.write("text")
      end
    end
    

    then:

    describe "foo" do
    
      it "should create 'filename' and put 'text' in it" do
        file = mock('file')
        File.should_receive(:open).with("filename", "w").and_yield(file)
        file.should_receive(:write).with("text")
        foo
      end
    
    end
    

    However, this approach falls flat in the presence of multiple reads/writes: simple refactorings which do not change the final state of the file can cause the test to break. In that case (and possibly in any case) you should prefer @Danny Staple's answer.

    0 讨论(0)
  • 2020-12-24 01:28

    I would suggest using StringIO for this and making sure your SUT accepts a stream to write to instead of a filename. That way, different files or outputs can be used (more reusable), including the string IO (good for testing)

    So in your test code (assuming your SUT instance is sutObject and the serializer is named writeStuffTo:

    testIO = StringIO.new
    sutObject.writeStuffTo testIO 
    testIO.string.should == "Hello, world!"
    

    String IO behaves like an open file. So if the code already can work with a File object, it will work with StringIO.

    0 讨论(0)
  • 2020-12-24 01:30

    For someone like me who need to modify multiple files in multiple directories (e.g. generator for Rails), I use temp folder.

    Dir.mktmpdir do |dir|
      Dir.chdir(dir) do
        # Generate a clean Rails folder
        Rails::Generators::AppGenerator.start ['foo', '--skip-bundle']
        File.open(File.join(dir, 'foo.txt'), 'w') {|f| f.write("write your stuff here") }
        expect(File.exist?(File.join(dir, 'foo.txt'))).to eq(true)
      end
    end  
    
    0 讨论(0)
  • 2020-12-24 01:38

    You can use fakefs.

    It stubs filesystem and creates files in memory

    You check with

    File.exists? "filename" 
    

    if file was created.

    You can also just read it with

    File.open 
    

    and run expectation on its contents.

    0 讨论(0)
  • 2020-12-24 01:43

    This is how to mock File (with rspec 3.4), so you could write to a buffer and check its content later:

    it 'How to mock File.open for write with rspec 3.4' do
      @buffer = StringIO.new()
      @filename = "somefile.txt"
      @content = "the content fo the file"
      allow(File).to receive(:open).with(@filename,'w').and_yield( @buffer )
    
      # call the function that writes to the file
      File.open(@filename, 'w') {|f| f.write(@content)}
    
      # reading the buffer and checking its content.
      expect(@buffer.string).to eq(@content)
    end
    
    0 讨论(0)
提交回复
热议问题