Add a warning when the should syntax is used. #339

Merged
merged 1 commit into from Sep 10, 2013

Conversation

Projects
None yet
5 participants
Member

samphippen commented Jul 4, 2013

This is for RSpec 3 with a view to letting users know that this syntax will be off by default in 4. I seem to recall that there was some discussion of this, but I couldn't find the exact issue/mailing list post. I'll bake one for rspec-expectations whilst I'm on the plane 🐱

Coverage Status

Coverage remained the same when pulling 44f35a5 on samphippen:warn_about_the_should_syntax into 6ef6f11 on rspec:master.

Contributor

alindeman commented Jul 4, 2013

Somehow I missed the decision. I thought since the should syntax doesn't have much maintenance cost, we had no plans to deprecate or remove it, except to start enabling it only in generated spec_helper.rb files.

Contributor

alindeman commented Jul 4, 2013

(If it's not obvious, I'm 👎 this change because this will spew warnings for all but the very newest test suites, and it's not entirely automatable to change the syntax)

Member

samphippen commented Jul 4, 2013

It warns precisely once for the entire suite as opposed to on every should.
It emits the warning once on the first should and then Not again. Hardly
"spewing warnings".

Sent from my phone please excuse my brevity.

On 4 Jul 2013, at 18:03, Andy Lindeman notifications@github.com wrote:

(If it's not obvious, I'm [image: 👎] this change because this will spew
warnings for all but the very newest test suites, and it's not entirely
automatable to change the syntax)


Reply to this email directly or view it on
GitHubhttps://github.com/rspec/rspec-mocks/pull/339#issuecomment-20484300
.

Member

samphippen commented Jul 4, 2013

I just worked out where the discussion was. It's on the 3.0 release post
gist. Won't link on case @myronmarston wants to keep it under wraps for
now. @alindeman you should have access to it :).

Sent from my phone please excuse my brevity.

On 4 Jul 2013, at 18:03, Andy Lindeman notifications@github.com wrote:

(If it's not obvious, I'm [image: 👎] this change because this will spew
warnings for all but the very newest test suites, and it's not entirely
automatable to change the syntax)


Reply to this email directly or view it on
GitHubhttps://github.com/rspec/rspec-mocks/pull/339#issuecomment-20484300
.

Coverage Status

Coverage remained the same when pulling f14c98f on samphippen:warn_about_the_should_syntax into 6ef6f11 on rspec:master.

Owner

myronmarston commented Jul 4, 2013

Somehow I missed the decision. I thought since the should syntax doesn't have much maintenance cost, we had no plans to deprecate or remove it, except to start enabling it only in generated spec_helper.rb files.

We have no plans to remove it. Given that we think the expect syntax is superior, and that we'd like to move in the direction of making rspec do zero monkey patching by default, the plan we had discussed was for should to still be enabled by default in RSpec 3 but to have it issue a "you should explicitly enable this" warning, and then in RSpec 4 it will be disabled by default. That'll help make our preference clear, and help nudge folks towards explicitly configuring the syntax if they want to continue using should.

Anyhow, let's hold off on this for now. I want to get community feedback on it first (based on the RSpec 3 blog post). There are plenty of other rspec 3 things we can work on in the meantime (e.g. removing stuff that's been deprecated for a long time).

Contributor

alindeman commented Jul 4, 2013

It warns precisely once for the entire suite as opposed to on every should. It emits the warning once on the first should and then Not again. Hardly "spewing warnings".

It's true. I didn't look closely enough. Sorry @samphippen.

We have no plans to remove it. Given that we think the expect syntax is superior, and that we'd like to move in the direction of making rspec do zero monkey patching by default, the plan we had discussed was for should to still be enabled by default in RSpec 3 but to have it issue a "you should explicitly enable this" warning, and then in RSpec 4 it will be disabled by default. That'll help make our preference clear, and help nudge folks towards explicitly configuring the syntax if they want to continue using should.

Ah, OK. Basically I misread the code and misinterpreted the text here. If it's possible to squash the warning by enabling the syntax explicitly, I'm supportive.

Sorry for the knee jerk reaction.

Owner

JonRowe commented Jul 5, 2013

👍 but also we need to hold off merging this until we get community feedback

Owner

myronmarston commented Jul 5, 2013

but also we need to hold off merging this until we get community feedback

Also, I have some code review feedback but don't have the time to write it up at the moment...

@JonRowe JonRowe and 1 other commented on an outdated diff Jul 5, 2013

lib/rspec/mocks/configuration.rb
@@ -43,13 +43,27 @@ def syntax
syntaxes << :expect if Syntax.expect_enabled?
syntaxes
end
+
+ def reset_syntaxes_to_default
+ self.syntax = [:should, :expect]
+ @should_warn_about_should = true
+ end
+
+ def warn_about_should
+ if @should_warn_about_should
+ Kernel.warn("Should style expectations will be disabled by default in the\
@JonRowe

JonRowe Jul 5, 2013

Owner

Should we not be using the deprecation handling code for this?

@myronmarston

myronmarston Aug 27, 2013

Owner

What @JonRowe said: this needs to use the normal deprecation APIs.

@myronmarston

myronmarston Aug 27, 2013

Owner

Also, I don't like using trailing \ to concatenate multiple lines. I'd prefer to see multiple strings +'d together as that's a more normal way to do it.

@myronmarston

myronmarston Aug 27, 2013

Owner

BTW, as far as this message goes, I'd like something like this:

RSpec.deprecate("Using the old `:should` syntax without explicitly enabling it.",
                :replacement => "the new `:expect` syntax or explicitly enable `:should`")

You should check how that reads with the standard formatting but I think that will read well.

Member

samphippen commented Aug 23, 2013

Should I close this but leave the branch around, I feel like we should maybe start with a community community poll first.

Owner

myronmarston commented Aug 23, 2013

@samphippen - The feedback to my RSpec 3 blog post (where I mentioned we would emit a warning like this) was universally positive. I consider that to be a sufficient poll.

Owner

myronmarston commented Aug 23, 2013

Thanks for reminding me to review this, though...I'll try to review it this weekend. If you want to rebase before then, feel free.

Member

samphippen commented Aug 23, 2013

@myronmarston go at it :D

Coverage Status

Coverage decreased (-0.09%) when pulling ff83d8a on samphippen:warn_about_the_should_syntax into 80d70b4 on rspec:master.

Member

samphippen commented Aug 26, 2013

@myronmarston plz review when you can ❤️

@myronmarston myronmarston commented on an outdated diff Aug 27, 2013

lib/rspec/mocks/syntax.rb
opts = {:expected_from => CallerFilter.first_non_rspec_line}
::RSpec::Mocks.expect_message(self, message.to_sym, opts, &block).never
end
def stub(message_or_hash, opts={}, &block)
+ ::RSpec::Mocks.configuration.warn_about_should
@myronmarston

myronmarston Aug 27, 2013

Owner

We want the warning to be in place for all of the methods added by the should syntax. that includes unstub, stub_chain, as_null_object, null_object?, received_message? and any_instance.

Actually, seeing all these methods makes me think that it would be beneficial if the warning message included the method name in it, so it should pass the method name through to the warn method you've defined. Maybe it could say something like:

RSpec.deprecate("Using :#{method_name} from the old `:should` syntax without explicitly enabling the syntax",
                :replacement => "the new `:expect` syntax or explicitly enable `:should`")

@myronmarston myronmarston and 1 other commented on an outdated diff Aug 27, 2013

lib/rspec/mocks/syntax.rb
opts[:expected_from] ||= CallerFilter.first_non_rspec_line
::RSpec::Mocks.expect_message(self, message.to_sym, opts, &block)
end
def should_not_receive(message, &block)
+ ::RSpec::Mocks.configuration.warn_about_should
@myronmarston

myronmarston Aug 27, 2013

Owner

I think warn_about_should is not the best name for this method...it makes it sound like we've deprecated any use of should and we haven't. Maybe warn_unless_should_configured instead?

@JonRowe

JonRowe Aug 27, 2013

Owner

👍 for warn_unless_should_configured

@myronmarston myronmarston commented on an outdated diff Aug 27, 2013

lib/rspec/mocks/configuration.rb
@@ -81,13 +81,26 @@ def transfer_nested_constants?
def transfer_nested_constants=(val)
@transfer_nested_constants = val
end
+
+ def reset_syntaxes_to_default
+ self.syntax = [:should, :expect]
+ @should_warn_about_should = true
@myronmarston

myronmarston Aug 27, 2013

Owner

If syntax is set after this it should set @should_warn_about_should to false, right? I don't see that anywhere.

Also, having should in the variable name twice is kinda weird. I think @warn_about_should is sufficient.

@myronmarston myronmarston and 1 other commented on an outdated diff Aug 27, 2013

spec/rspec/mocks/configuration_spec.rb
@@ -85,6 +85,11 @@ def sandboxed
expect(configured_syntax).to eq([:should])
end
+ it "does not warn about the should syntax" do
+ Kernel.should_not_receive(:warn).with(/style expectations/i)
+ Object.new.should_not_receive(:nil?)
@myronmarston

myronmarston Aug 27, 2013

Owner

nil? is one of those methods that I would never recommend stubbing or mocking. As such, it would be nice not to use it in an example here.

@myronmarston myronmarston and 1 other commented on an outdated diff Aug 27, 2013

spec/rspec/mocks/configuration_spec.rb
@@ -85,6 +85,11 @@ def sandboxed
expect(configured_syntax).to eq([:should])
end
+ it "does not warn about the should syntax" do
+ Kernel.should_not_receive(:warn).with(/style expectations/i)
@myronmarston

myronmarston Aug 27, 2013

Owner

Given that this is a negative expectation, I don't think it should use with. with with a negative expectation is prone to becoming a false positive if the warning text changes.

@JonRowe

JonRowe Aug 27, 2013

Owner

Shouldn't receive warn at all IMO.

Owner

myronmarston commented Aug 27, 2013

@samphippen - code review feedback left.

Coverage Status

Coverage increased (+0.38%) when pulling 23eb526 on samphippen:warn_about_the_should_syntax into 80d70b4 on rspec:master.

Member

samphippen commented Sep 3, 2013

@myronmarston I took a quick look through your comments, I think I got them all, I added a spec for the default then should case you asked about, you were right it wasn't doing the right thing, but it does now. More review welcomed. (Also got some help from @JonRowe on this one when we bumped into each other today in london)

@myronmarston myronmarston commented on an outdated diff Sep 4, 2013

lib/rspec/mocks/configuration.rb
+
+ def reset_syntaxes_to_default
+ self.syntax = [:should, :expect]
+ @warn_about_should = true
+ end
+
+ def warn_unless_should_configured(method_name)
+ if @warn_about_should
+ RSpec.deprecate(
+ "Using #{method_name} from the old `:should` syntax without explicitly enabling the syntax.",
+ :replacement => "the new `:expect` syntax or explicitly enable `:should`"
+ )
+
+ @warn_about_should = false
+ end
+ end
@myronmarston

myronmarston Sep 4, 2013

Owner

You know, I'm thinking that this method doesn't really belong here: Configuration is for public configuration methods, not for private RSpec implementation details. I'd consider this to be a private method, not intended to be called by end users. Also, instructing a config option to emit a warning is a bit odd. (Why should the config object have that responsibility?)

Maybe it belongs on the Syntax module instead? Thoughts?

@myronmarston myronmarston commented on the diff Sep 4, 2013

spec/rspec/mocks/configuration_spec.rb
+ o = Object.new
+ o2 = Object.new
+
+ o.stub(:faces)
+ o2.stub(:faces)
+ end
+
+ it "doesn't warn about stubbing after a reset and setting should" do
+ expect(RSpec).not_to receive(:deprecate)
+ RSpec::Mocks.configuration.reset_syntaxes_to_default
+ RSpec::Mocks.configuration.syntax = :should
+ o = Object.new
+ o2 = Object.new
+ o.stub(:faces)
+ o2.stub(:faces)
+ end
@myronmarston

myronmarston Sep 4, 2013

Owner

Given that we've had some trouble with this, I'd like a spec that asserts on the correct call site being included in the deprecation warning.

@samphippen

samphippen Sep 8, 2013

Member

you mean add the call site to the expected_arguments list, slightly confused because you've put this next to the negative case that doesn't filter by arguments. I assume you only want this to happen on the ones that do args matching?

@samphippen

samphippen Sep 8, 2013

Member

I just had another look at this, it'd change the expect to kernel#warn instead of rspec#deprecate. Based on looking at this I'd assume we have tests elsewhere for call sites from CallerFilter? if not would you go for something like expect(CallerFilter).to receive(:first_non_rspec_line).and_return(the correct things here)?

@myronmarston

myronmarston Sep 8, 2013

Owner

you mean add the call site to the expected_arguments list, slightly confused because you've put this next to the negative case that doesn't filter by arguments. I assume you only want this to happen on the ones that do args matching?

No, I would like an additional spec added specifically for this. Having a spec for it calls it out as important (which it is).

Based on looking at this I'd assume we have tests elsewhere for call sites from CallerFilter

No, setting a mock expectation on CallerFilter doesn't really help us here; consider that a few weeks back, we had two different deprecation warnings that were printing the wrong call site, and both were using the CallerFilter (or the equivalent, before that got added):

  • in rspec-expectations, the be_true deprecation was printing a line from rspec/matchers.rb, because the caller-searching logic considered rspec/matchers/*.rb to be an rspec file but not rspec/matchers.rb. Luckily, CallerFilter as added to rspec-mocks already handled this correctly, so I ported it to rspec-core to solve the bug.
  • in rspec-mocks, the deprecation for the any_instance receiver yielding was printing a line from the user's code but the wrong line, because we wanted it to print the line where the implementation block was defined, but the warning was triggered when the mocked/stubbed method was called, and thus CallerFilter was being given the wrong backtrace to begin with.

To really have confidence that the right line is being printed, we need a spec that actually asserts on the file and line number (typically with __FILE__ and __LINE__ so that it won't fail as new code is added to the file or if the file is renamed). We have a helper method in rspec-core that assists with testing this. I recommend porting that to here (eventually, I suspect it'll go into the rspec-support gem we've discussed) and then you can test this like so:

it "includes the call site in the deprecation warning" do
  obj = Object.new
  expect_deprecation_with_call_site(__FILE__, __LINE__ + 1)
  obj.stub(:faces)
end

Does that make sense?

@samphippen

samphippen Sep 9, 2013

Member

I think so, I'll have an experiment and work it out.

Owner

myronmarston commented Sep 4, 2013

Looking good. Very close to being ready to merge :). Left a couple final comments. (Sorry about noticing some of this on the last review...).

Also, Update should warnings for myron's changes. is kinda a weird commit message. I haven't made any changes here.

Member

samphippen commented Sep 8, 2013

Also, Update should warnings for myron's changes. is kinda a weird commit message. I haven't made any changes here.

you're totally right. tired git driving leads to bad commit messages. I'll squash everything together once I'm done here.

Coverage Status

Coverage decreased (-0.16%) when pulling 75f9f60 on samphippen:warn_about_the_should_syntax into 3ac6f4e on rspec:master.

@samphippen samphippen Add a warning when the should syntax is used.
Signed-off-by: Sam Phippen <samphippen@googlemail.com>
cf4d4c9
Member

samphippen commented Sep 9, 2013

@myronmarston please rereview when you can. I took most of your notes. Good catches

Coverage Status

Coverage remained the same when pulling cf4d4c9 on samphippen:warn_about_the_should_syntax into 3ac6f4e on rspec:master.

myronmarston merged commit 44b464e into rspec:master Sep 10, 2013

1 check passed

default The Travis CI build passed
Details
Owner

myronmarston commented Sep 10, 2013

Thanks, @samphippen! I just merged it. I also added some additional doc comments in f96edc3.

Can you take care of adding this kind of thing to rspec-expectations as well?

Owner

myronmarston commented Sep 10, 2013

Also, BTW: while it's nice to not a ton of tiny commits to merge, in the future please don't continually amend your commits as we do the back-and-forth of a code review. It makes it harder to see what changed since I last looked at the PR when you've amended commits or squashed them together.

@myronmarston myronmarston added a commit that referenced this pull request Sep 10, 2013

@myronmarston myronmarston Add changelog entry for #339.
[ci skip]
b34488c
Owner

myronmarston commented Sep 10, 2013

One other thing...we forgot a changelog entry. I added one in b34488c

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