Add `and_invoke` for sequential mixed (return/raise) responses.
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.