Search code examples
rubylambdatestunitruby-mocha

How do you mock a method like "each"?


I'm trying to test a method that uses CSV.foreach to read in a csv file and does some processing on it. It looks something like this:

require 'csv'

class Csv_processor
  def self.process_csv(file)
    begin
      CSV.foreach(file) do { |row|
        # do some processing on the row
      end
    rescue CSV::MalformedCSVError
      return -1
    end
  end
end

CSV.foreach takes a file path as input, reads the file and parses the comma separated values, returning an array for each row in the file. Each array is passed in turn to the code block for processing.

I'd like to use Mocha to stub the foreach method so I can control the input to the process_csv method from my test without any file I/O mumbo-jumbo.

So the test would be something like this

test "rejects input with syntax errors" do
  test_input = ['"sytax error" 1, 2, 3', '4, 5, 6', '7, 8, 9']
  CSV.expects(:foreach).returns( ??? what goes here ??? )
  status = Csv_processor.process_csv("dummy")
  assert_equal -1, status, "Status does not indicate error: #{status}"
end

I need a way to turn my test_input array into something Mocha can work with. I think I have to use some sort of proc or lambda, but I find the world of procs, blocks and lambdas a bit of a mind-bender.


Solution

  • Use Mocha::Expectations#multiple_yields:

    CSV.expects(:foreach).multiple_yields([row_array1], [row_array2], ...)
    

    Check this thread to see why you have to pass the rows inside another array.