RSpec waving 'bye bye' to implicit module inclusion
May 29th, 2008
Until sometime very soon, when you describe a module in RSpec using this syntax:
describe SomeModule do ... end
RSpec implicitly includes that module in the example group. This allows you to do this:
describe CatLikeBehaviour do
it "should say 'meow' when it greets you" do
say_hello.should == 'meow'
end
end
module CatLikeBehaviour do
def say_hello
'meow'
end
end
As is often the case with things implicit, this actually turns out to be a problem. The problem revealed itself most notably when an RSpec user reported that a describe() method in a module he was using was conflicting with RSpec’s describe() method.
One response to that thread suggested that using describe() in a module might be too generic, but I think that really hides the point. Imagine how frustrated you would get if you had examples of a module with a current? method and we decided to add a current? method to Spec::Example::ExampleGroupMethods. You’d suddenly start seeing those examples fail with stack traces eminating from RSpec instead of your code. Not good.
And so, we are going to be removing this feature.
With the 1.1.4 release, you get a warning any time that the example calls a method on self that is part of the included module. Soon it will be removed entirely.
rails helper examples
The biggest impact of this is going to be felt in rspec-rails helper examples. There are two remedies that you have if you’ve got examples that send messages to self that should be going to another object:
1. use the new helper object provided by HelperExampleGroup
describe DateHelper do
it "should format the date as mm/dd/yyyy" do
helper.format_date(Date.new(2008, 5, 31)).should == '05/31/2008'
end
end
The helper object is an instance of ActionView::Base with the named module included in it, so it has access to everything else that it should have.
2. include the module explicitly
describe DateHelper do
include DateHelper
it "should format the date as mm/dd/yyyy" do
format_date(Date.new(2008, 5, 31)).should == '05/31/2008'
end
end
My recommendation is definitely the first option as I find it more expressive.
I realize this is API changing and backward-compatibility breaking, but this is one of those cases where, at least in my view, the pain is justified by the result.
8 Responses to “RSpec waving 'bye bye' to implicit module inclusion”
Sorry, comments are closed for this article.


July 13th, 2008 at 06:06 AM
“I realize this is API changing and backward-compatibility breaking…”
While this may be true, I don’t personally think your are wrong. You could almost view this as a usage bugs.
Bugs need to be fixed :-)
July 13th, 2008 at 06:06 AM
Yesterday I was thinking that using object named helper should be the way to do helper testing, great timing! I think this change is good even if some fixing is needed on my tests.
July 13th, 2008 at 06:06 AM
What if describe could detect method calls in the do-block that should’ve had helper prepended to them, and just route those over to helper automagically?
July 13th, 2008 at 06:06 AM
What if describe could detect method calls in the do-block that should’ve had helper prepended to them, and just route those over to helper automagically?
July 13th, 2008 at 06:06 AM
+1 on this change, and +1 on favoring option #1 under the rails helper example. For modules that aren’t rails helpers, it’s easy enough to use the same approach.
July 13th, 2008 at 06:06 AM
Whenever I make this change I seem to be getting “The error occurred while evaluation nil.url_for” in all my named routes in the specs. Is the preferred method of doing routes in specs now to stub them out in the helper object?
July 13th, 2008 at 06:06 AM
@Michael – actually, that’s a bug. For right now you’d be best just ignoring the warnings. I’ll get a fix in shortly.
July 13th, 2008 at 06:06 AM
@Michael – fixed in a46a78d