-
-
Notifications
You must be signed in to change notification settings - Fork 357
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow multiple message allowances/expectations via receive_messages
#399
Conversation
receiver.send(method_name,subject,&block) | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like a lot of overhead to go through to repeatedly delegate to the Receive
matcher here (which in turn delegates to a more fundamental underlying mechanism). Among other things, if you have provided a hash of 6 messages, the receive
matchers will each get the mock proxy individually, causing 6 mock proxy lookups when one would suffice.
What would it look like to bypass the receive
matcher?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's the same as setting up each expectation / allowance, so it's no additional overhead, but it looked to me like it would involve a fair amount of repetition to extract this out...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, in #401 @xaviershay has some perf improvements that this PR should take advantage of, I think: he's introduced the concept of a "simple stub" for these sorts of message/return-value pairs, and it looks to greatly improve perf.
So, I'm thinking we should merge his PR first (it sounds like he'll address my feedback soon and it's very close to being ready to merge) and then refactor this to use add_simple_stub
under the covers.
Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like that idea, I'll take a look when it's merged.
As promised, refactored to use the improvements from #401 |
@@ -28,6 +28,7 @@ | |||
require 'rspec/mocks/mutate_const' | |||
require 'rspec/mocks/matchers/have_received' | |||
require 'rspec/mocks/matchers/receive' | |||
require 'rspec/mocks/matchers/receives_messages' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The matcher is receive_messages
not receives_messages
....shouldn't the file be named accordingly?
@message_return_value_hash.each do |message, value| | ||
yield host, message, value | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is much more readable/understandable than the map_on
thing you had before. Thanks!
One suggestion, though: given that the host
argument is just yielded back to the caller, it seems a bit unnecessary. The name of this method also suggests that this method does something with it or uses it to determine what messages to yield.
Is there a reason you chose to pass it through? I'd probably (slightly) favor just putting a host = blah
line at the call sites and then change this to each_message
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I liked the look of passing it in and out rather than having a local variable, that was all
#401 is broken, if it needs to be re-implemented this patch will have to change too. I need to understand how this PR interacts with it. Didn't leave myself enough time to do that tonight, unfortunately. |
end | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to see some specs that document how .not_to receive_messages
is handled. Can you add those?
@myronmarston I've added in specs covering what happens when you attempt to use the negative (I'm disallowing it) but I'm having trouble consistently getting a partial mocking failure. What should trigger it? I don't want to create order dependant specs... |
Ping! Any advice? |
end | ||
rescue RSpec::Mocks::MockExpectationError => error | ||
error.backtrace.insert(0, @backtrace_line) | ||
Kernel::raise error | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic in this method (particularly the rescue and backtrace insertion bit) is very similar to what's already here:
rspec-mocks/lib/rspec/mocks/message_expectation.rb
Lines 247 to 252 in 3ac6f4e
def verify_messages_received | |
generate_error unless expected_messages_received? || failed_fast? | |
rescue RSpec::Mocks::MockExpectationError => error | |
error.backtrace.insert(0, @expected_from) | |
Kernel::raise error | |
end |
Can some common logic be extracted?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactored
I'll squash this before we merge it but I'm leaving the history until I'm ready for that :) |
|
||
# Insert original locations into stacktraces | ||
# @api private | ||
class BacktrackRestore |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BacktrackRestore
is a very odd name. I have no idea what the name has to do with what the code below does...
I don't have a better name idea yet, though :(.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've changed to InsertOntoBacktrace.line
Ok, this now resets partial mocks properly (it was actually a fairly trivial change as we have a separate One thing I haven't done, and this is deliberate cause my head hurts just thinking about it, is handle resetting 'any_instance' stubs/expectations, because they are already reset entirely separately from everything else, and I'm using the existing stub/expectation functionality for those (it's not new code). They already don't reset cleanly, so I figure that's a new issue. |
That's news to me. Can you open an rspec-mocks issue includes a code snippet that demonstrates the problem? |
Allow multiple message allowances/expectations via `receive_messages`
Merged. Thanks @JonRowe! |
Weren't we going to squash this? :P |
Oh yeah.....too late now, I guess. |
Yup, oh well :) |
👍 |
Further to #368 this allow multiple message allowances/expectations via
receive_messages
.