Skip to content
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

Merged
merged 28 commits into from
Sep 12, 2013

Conversation

JonRowe
Copy link
Member

@JonRowe JonRowe commented Aug 9, 2013

Further to #368 this allow multiple message allowances/expectations via receive_messages.

receiver.send(method_name,subject,&block)
end
end
end
Copy link
Member

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?

Copy link
Member Author

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...

Copy link
Member

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?

Copy link
Member Author

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.

@JonRowe
Copy link
Member Author

JonRowe commented Aug 12, 2013

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'
Copy link
Member

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
Copy link
Member

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.

Copy link
Member Author

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

@JonRowe
Copy link
Member Author

JonRowe commented Aug 13, 2013

Whats the story with #401 and #404 and this?

@xaviershay
Copy link
Member

#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
Copy link
Member

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?

@JonRowe
Copy link
Member Author

JonRowe commented Aug 19, 2013

@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...

@JonRowe
Copy link
Member Author

JonRowe commented Sep 3, 2013

Ping! Any advice?

end
rescue RSpec::Mocks::MockExpectationError => error
error.backtrace.insert(0, @backtrace_line)
Kernel::raise error
end
Copy link
Member

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:

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?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored

@JonRowe
Copy link
Member Author

JonRowe commented Sep 9, 2013

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
Copy link
Member

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 :(.

Copy link
Member Author

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

@coveralls
Copy link

Coverage Status

Coverage decreased (-0.06%) when pulling c3bdeff on receive_messages into 3ac6f4e on master.

@JonRowe
Copy link
Member Author

JonRowe commented Sep 9, 2013

Ok, this now resets partial mocks properly (it was actually a fairly trivial change as we have a separate PartialMockProxy to handle this).

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.

@myronmarston
Copy link
Member

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?

myronmarston added a commit that referenced this pull request Sep 12, 2013
Allow multiple message allowances/expectations via `receive_messages`
@myronmarston myronmarston merged commit 69954e9 into master Sep 12, 2013
@myronmarston myronmarston deleted the receive_messages branch September 12, 2013 01:35
@myronmarston
Copy link
Member

Merged. Thanks @JonRowe!

@JonRowe
Copy link
Member Author

JonRowe commented Sep 12, 2013

Weren't we going to squash this? :P

@myronmarston
Copy link
Member

Oh yeah.....too late now, I guess.

@JonRowe
Copy link
Member Author

JonRowe commented Sep 12, 2013

Yup, oh well :)

@rosenfeld
Copy link

👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants