map7
map7

Reputation: 5126

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.

Upvotes: 20

Views: 15557

Answers (2)

Laura
Laura

Reputation: 178

Stubbing File.open breaks pry. To avoid this you can stub CSV.read, which isn't as robust as stubbing file, but will let you use pry:

    let(:data) do
      StringIO.new <<-CSV_DATA
        0;48;78;108;279;351;405;694;872;1696
        1.03;9.28;13.4;18.56;29.9;30.93;42.27;77.32;85.57;100.0
        0.0;2.94;8.82;11.76;44.12;97.06;100.0;100.0;100.0;100.0
      CSV_DATA
    end
    let(:csv_config) { { headers: true, return_headers: true, converters: :numeric } }
    
    before { allow(CSV).to receive(:read).with(csv_path, csv_config) { CSV.parse(data, csv_config) } }     

Upvotes: 1

zetetic
zetetic

Reputation: 47548

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)

Upvotes: 34

Related Questions