Don't silently ignore arbitrary method expectations when combining them with 'and_call_original' #382
Conversation
Awesome, thx! |
|
||
extend(Mocks::Warning) unless respond_to?(:warning) && respond_to?(:warn_with) | ||
end | ||
|
myronmarston
Jul 31, 2013
Member
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?
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?
myronmarston
Jul 31, 2013
Member
Also, do you think this kind of warning should be printed in the deprecation stream or always to STDERR?
Also, do you think this kind of warning should be printed in the deprecation stream or always to STDERR?
JonRowe
Jul 31, 2013
Author
Member
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 :)
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 :)
JonRowe
Oct 1, 2013
Author
Member
Really wishing I had noted the number...
Really wishing I had noted the number...
JonRowe
Oct 2, 2013
Author
Member
Ah hah! Yes that makes sense :)
Ah hah! Yes that makes sense :)
@@ -22,24 +22,30 @@ def self.new_instance | |||
let(:instance) { klass.new } | |||
|
|||
it 'passes the received message through to the original method' do | |||
instance.should_receive(:meth_1).and_call_original | |||
allow(instance).to receive(:meth_1).and_call_original |
myronmarston
Jul 31, 2013
Member
Why did you change this from a message expectation to a stub? IMO, and_call_original
doesn't really make sense with a stub, given that the and_call_original
is only possible on a partial mock, and it would call the original normally anyway....
Why did you change this from a message expectation to a stub? IMO, and_call_original
doesn't really make sense with a stub, given that the and_call_original
is only possible on a partial mock, and it would call the original normally anyway....
expect(instance.meth_1).to eq(:original) | ||
end | ||
|
||
it 'passes args and blocks through to the original method' do | ||
instance.should_receive(:meth_2).and_call_original | ||
allow(instance).to receive(:meth_2).and_call_original |
myronmarston
Jul 31, 2013
Member
Same here: why the change from a mock expectation?
Same here: why the change from a mock expectation?
@@ -116,6 +116,9 @@ def and_call_original | |||
if @method_double.object.is_a?(RSpec::Mocks::TestDouble) | |||
@error_generator.raise_only_valid_on_a_partial_mock(:and_call_original) | |||
else | |||
if implementation.inner_action |
myronmarston
Jul 31, 2013
Member
I think implementation.has_inner_action?
would make more sense...thoughts?
I think implementation.has_inner_action?
would make more sense...thoughts?
@@ -464,6 +467,7 @@ def initial_implementation_action=(action) | |||
end | |||
|
|||
def inner_implementation_action=(action) | |||
RSpec.warning("You're overriding a previous implementation for this stub") if implementation.inner_action |
myronmarston
Jul 31, 2013
Member
I think RSpec.warn
reads better (as its a verb) than RSpec.warning
(as warning
is a noun). Thoughts?
I think RSpec.warn
reads better (as its a verb) than RSpec.warning
(as warning
is a noun). Thoughts?
JonRowe
Oct 2, 2013
Author
Member
This matches up with the stuff in rspec/rspec-core#1024, happy to have that discussion there :)
This matches up with the stuff in rspec/rspec-core#1024, happy to have that discussion there :)
@@ -116,6 +116,9 @@ def and_call_original | |||
if @method_double.object.is_a?(RSpec::Mocks::TestDouble) | |||
@error_generator.raise_only_valid_on_a_partial_mock(:and_call_original) | |||
else | |||
if implementation.inner_action | |||
RSpec.warning("You're overriding a previous implementation for this stub") |
myronmarston
Jul 31, 2013
Member
I think the "for this stub" language could be a bit confusing when it's a mock expectation and not a stub. Not sure if there's a more generic way to phrase it, though...
I think the "for this stub" language could be a bit confusing when it's a mock expectation and not a stub. Not sure if there's a more generic way to phrase it, though...
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 ( |
Changes Unknown when pulling d8bca94 on warn_when_overriding_implementation into * on master*. |
Changes Unknown when pulling 650bee8 on warn_when_overriding_implementation into * on master*. |
Changes Unknown when pulling 650bee8 on warn_when_overriding_implementation into * on master*. |
Ready for a review I guess. |
@@ -0,0 +1,31 @@ | |||
module RSpec | |||
|
|||
unless respond_to?(:deprecate) |
xaviershay
Oct 5, 2013
Member
Where else would this be defined? Comment required.
Where else would this be defined? Comment required.
JonRowe
Oct 5, 2013
Author
Member
This whole file is for when the gems are used individually.
This whole file is for when the gems are used individually.
xaviershay
Oct 5, 2013
Member
Otherwise it picks up the one from rspec-core
. I get it, think it's unusual enough to deserve a comment.
Otherwise it picks up the one from rspec-core
. I get it, think it's unusual enough to deserve a comment.
JonRowe
Oct 5, 2013
Author
Member
Yep I was already writing one ;)
Yep I was already writing one ;)
Could final commit be squashed into another? |
Looks good otherwise when build is green. |
It's awaiting rspec/rspec-core#1024 (to sync the warning stuff) |
Changes Unknown when pulling 894dd8b on warn_when_overriding_implementation into * on master*. |
Actually I think we can merge this now and sync up the warnings stuff later if need be |
module RSpec | ||
|
||
# We don't redefine the deprecation helpers | ||
# when they already exist (defined by rspec-core etc) |
xaviershay
Oct 5, 2013
Member
good
good
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. |
Changes Unknown when pulling 659b039 on warn_when_overriding_implementation into * on master*. |
Don't silently ignore arbitrary method expectations when combining them with 'and_call_original'
This looks good, but did we address the other odd error ( |
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. |
Ah...I know what's going on: that expression passes the block to rspec-mocks/lib/rspec/mocks/matchers/receive.rb Lines 76 to 78 in f434af5 So, I think if we changed |
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.
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
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.