Skip to content

Add `and_invoke` for sequential mixed (return/raise) responses.

gitlab-qa-bot requested to merge github/fork/askreet/and_invoke into main

Created by: askreet

In tests I occasionally encounter things like this:

called = false
allow(mock_api).to receive(:put_something) do
  # raise first call, second call succeeds
  unless called
    called = true
    raise ApiError, "Some Failure!"
  end
  :some_useful_value
end

It's commonly suggested to do similar things on StackOverflow, for example. It seemed a common enough problem to try to generalize a solution that is a bit more readable. This patch allows the following alternative:

allow(mock_api).to receive(:put_something).and_invoke(-> { raise ApiError, "Some Failure!" },
                                                      -> { :some_useful_value })

and_invoke behaves like and_return with regards to sequential calls, matching expected call counts, and repeating the last call indefinitely in cases where allow is used vs. expect with exactly(n).times.

I alternatively considered some more magical approaches like:

allow(mock_api).to receive(:put_something).and_return_or_raise(ApiError.new("Some Failure!"), true)
allow(mock_api).to receive(:put_something).chain_response
                                          .and_raise(RuntimeError, "Some Failure!")
                                          .and_return(true)

Ultimately, I thought Procs were more "native", if slightly ugly.

Merge request reports