Search code examples
ruby-on-railsfilemockingrspecrspec2

rspec test result from csv.read mocking file


I'm using ruby 1.9 and I'm trying to do BDD. My first test 'should read in the csv' works, but the second where I require a file object to be mocked doesn't.

Here is my model spec:

require 'spec_helper'

describe Person do
  describe "Importing data" do
    let(:person) { Person.new }

    let(:data) { "title\tsurname\tfirstname\t\rtitle2\tsurname2\tfirstname2\t\r"}
    let(:result) {[["title","surname","firstname"],["title2","surname2","firstname2"]] }

    it "should read in the csv" do
      CSV.should_receive(:read).
        with("filename", :row_sep => "\r", :col_sep => "\t")
      person.import("filename")
    end

    it "should have result" do
      filename = mock(File, :exists? => true, :read => data)
      person.import(filename).should eq(result)
    end
  end
end

Here is the code so far:

class Person < ActiveRecord::Base
  attr_accessor :import_file

  def import(filename)
    CSV.read(filename, :row_sep => "\r", :col_sep => "\t")
  end
end

I basically want to mock a file so that when the CSV method tries to read from the file it returns my data variable. Then I can test if it equals my result variable.


Solution

  • You can stub File.open:

    let(:data) { "title\tsurname\tfirstname\rtitle2\tsurname2\tfirstname2\r" }
    let(:result) {[["title","surname","firstname"],["title2","surname2","firstname2"]] }
    
    it "should parse file contents and return a result" do
      expect(File).to receive(:open).with("filename","rb") { StringIO.new(data) }
      person.import("filename").should eq(result)
    end
    

    StringIO essentially wraps a string and makes it behave like an IO object (a File in this case)