How to use different parameter values in an RSpec mock/stub?

755 Views Asked by At

My program downloads a zip file from the web then parses it. The relevant parsing-related code is:

Zip::File.open("real_file.zip") do |zip_file|
  # do stuff
end

In my RSpec test environment, I'd like to stub this code to parse a fake/mock file instead of the real one. Specifically, I'd like to replace the parameter value "real_file.zip" with "mock_file.zip".

I tried the following approach:

allow(Zip::File).to receive(:open).and_return(Zip::File.open("mock_file.zip"))

... but this prevents execution of code inside the block (# do stuff). I don't want the mock file contents to be returned by the method, but rahter to be assigned to the value of zip_file for further use. How can this be achieved?

1

There are 1 best solutions below

1
On BEST ANSWER

Here's what you want to do:

mock_file = Zip::File.open('mock_file.zip')
allow(Zip::File).to receive(:open) { |&block| block.call(mock_file) }

What you're doing here is yielding a value to the block in your original code. The problem with simply returning a scalar value is that it doesn't yield anything to your block so it won't be called. Note that I'm opening the mock file before putting in the message expectation since it would also intercept your call to Zip::File.open and cause a nice stack overflow.

More information: https://www.relishapp.com/rspec/rspec-mocks/v/3-2/docs/configuring-responses/block-implementation#yield-to-the-caller's-block