Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 291
map7 Avatar asked Mar 07 '11 11:03

map7


2 Answers

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)

like image 162
zetetic Avatar answered Nov 04 '22 20:11

zetetic


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) } }     

like image 1
Laura Avatar answered Nov 04 '22 20:11

Laura