Skip to content
This repository was archived by the owner on Nov 30, 2024. It is now read-only.

Conversation

@JonRowe
Copy link
Member

@JonRowe JonRowe commented Jul 28, 2013

I had a discussion with @myronmarston about a problem I ran into during the conversion of our RSpec suite to the new expect/allow syntax. The gist of it can be found here.

Funnily what I thought was a bug, never quite worked the way I thought it was and I refactored the spec after reading his suggestions. Myron asked me to also add an issue for it, though. So here we go :-)

The spec we talked about had used the following expectation.

CachedUser.should_receive(:where) do |args|
    expect(args[:id]).to have(3).items
    expect(contact_ids).to include(*args[:id])
end.and_call_original

The values passed to 'where' are sort of random so you can't really setup an argument matcher with 'with'. That's why we tried to verify them in the block. The whole code under test there was also part of an AREL call comparable to this one. That's where the 'and_call_original' came into the game

CachedUser.where(id: random_related_user_ids).all

The spec passed. Though, as Myron pointed out, 'and_call_original' completely replaces the block expectation, resulting in the inner expectations never to be executed.

That was a bit surprising to find out, but to be honest also a fault on my side, since I probably never saw the expectation fail in the first place :-/

To make that behavior more obvious I think it would be good to either raise an exception or to output a warning in that case.

@coveralls
Copy link

Coverage Status

Coverage decreased (-0%) when pulling c05a378 on warn_when_overriding_implementation into 9202615 on master.

@BjRo
Copy link
Author

BjRo commented Jul 28, 2013

Awesome, thx!

Copy link
Member

Choose a reason for hiding this comment

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

This file is really small and seems to have a lot in common with lib/rspec/mocks/deprecation.rb. Given that ruby (particularly 1.9) has had well-known perf problems with requires, I think it behooves us to not split things into so many small files. What do you think about combining these into one file?

Copy link
Member

Choose a reason for hiding this comment

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

Also, do you think this kind of warning should be printed in the deprecation stream or always to STDERR?

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 taken care of this in the other PR, and I will rebase off that when we've worked it into something we want to use :)

Copy link
Member

Choose a reason for hiding this comment

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

@JonRowe which other PR? Has it been merged yet and can we move forward with this fix?

Copy link
Member Author

Choose a reason for hiding this comment

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

Really wishing I had noted the number...

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah hah! Yes that makes sense :)

@myronmarston
Copy link
Member

In @BjRo's gist, it also came up that an expression like this:

      expect(CachedUser).to receive(:where) do |args|
        expect(args[:id]).to have(3).items
        expect(contact_ids).to include(*args[:id])
      end.and_call_original

...raises a confusing error (NoMethodError: undefined method 'and_call_original' for []:Array). It would be good to fix that as well.

@coveralls
Copy link

Coverage Status

Changes Unknown when pulling d8bca94 on warn_when_overriding_implementation into * on master*.

@coveralls
Copy link

Coverage Status

Changes Unknown when pulling 650bee8 on warn_when_overriding_implementation into * on master*.

@coveralls
Copy link

Coverage Status

Changes Unknown when pulling 650bee8 on warn_when_overriding_implementation into * on master*.

@JonRowe
Copy link
Member

JonRowe commented Oct 2, 2013

Ready for a review I guess.

Copy link
Member

Choose a reason for hiding this comment

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

Where else would this be defined? Comment required.

Copy link
Member Author

Choose a reason for hiding this comment

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

This whole file is for when the gems are used individually.

Copy link
Member

Choose a reason for hiding this comment

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

Otherwise it picks up the one from rspec-core. I get it, think it's unusual enough to deserve a comment.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep I was already writing one ;)

@xaviershay
Copy link
Member

Could final commit be squashed into another?

@xaviershay
Copy link
Member

Looks good otherwise when build is green.

@JonRowe
Copy link
Member

JonRowe commented Oct 5, 2013

It's awaiting rspec/rspec-core#1024 (to sync the warning stuff)

@coveralls
Copy link

Coverage Status

Changes Unknown when pulling 894dd8b on warn_when_overriding_implementation into * on master*.

@JonRowe
Copy link
Member

JonRowe commented Oct 5, 2013

Actually I think we can merge this now and sync up the warnings stuff later if need be

Copy link
Member

Choose a reason for hiding this comment

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

good

@xaviershay
Copy link
Member

Yeah I don't see a reason to gate this on the core PR. Worst case scenario we just need to come back here and change it again if core PR changes, that's not terrible.

@coveralls
Copy link

Coverage Status

Changes Unknown when pulling 659b039 on warn_when_overriding_implementation into * on master*.

JonRowe added a commit that referenced this pull request Oct 5, 2013
Don't silently ignore arbitrary method expectations when combining them with 'and_call_original'
@JonRowe JonRowe merged commit f434af5 into master Oct 5, 2013
@JonRowe JonRowe deleted the warn_when_overriding_implementation branch October 5, 2013 02:41
@myronmarston
Copy link
Member

This looks good, but did we address the other odd error (NoMethodError: undefined method 'and_call_original' for []:Array) I mentioned above ?

@JonRowe
Copy link
Member

JonRowe commented Oct 5, 2013

Hmm, no, but thats a block capture issue... e.g.

expect(user).to receive(:where) do |args|
  expect(args[:id].size).to eq 3
end.and_call_original

produces the weird error

expect(user).to( receive(:where) do |args|
  expect(args[:id].size).to eq 3
end.and_call_original )

Works fine.

@myronmarston
Copy link
Member

Ah...I know what's going on: that expression passes the block to to due to ruby's precedence rules. So and_call_original is being called from the return value of to. which is the return value of handle_matcher, which returns whatever matcher.matches? returns, which, in this case, is returning @recorded_customizations, which is an array:

@recorded_customizations.each do |customization|
customization.playback_onto(expectation)
end

So, I think if we changed RSpec::Mocks::Matchers::Recive#setup_method_substitute to return expectation, it would allow further chaining. Want to take a stab at writing a failing spec, adding that, and seeing if it passes?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants