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.

<p>One response to that thread suggested that using <code>describe()</code> 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 <code>current?</code> method and we decided to add a <code>current?</code> method to <code>Spec::Example::ExampleGroupMethods</code>. You&#8217;d suddenly start seeing those examples fail with stack traces eminating from RSpec instead of your code. Not good.</p>


<p>And so, we are going to be removing this feature.</p>


<p>With the 1.1.4 release, you get a warning any time that the example calls a method on <code>self</code> that is part of the included module. Soon it will be removed entirely.</p>


<h3>rails helper examples</h3>


<p>The biggest impact of this is going to be felt in rspec-rails helper examples. There are two remedies that you have if you&#8217;ve got examples that send messages to <code>self</code> that should be going to another object:</p>


<p>1. use the new <code>helper</code> object provided by <code>HelperExampleGroup</code></p>

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.

<p>2. include the module explicitly</p>

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.

<p>I realize this is <span class="caps">API</span> 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.</p>

8 Responses to “RSpec waving 'bye bye' to implicit module inclusion”

  1. Chris Kilmer Says:

    “I realize this is API changing and backward-compatibility breaking…”

    <p>While this may be true, I don&#8217;t personally think your are wrong.  You could almost view this as a usage bugs.</p>
    
    
    <p>Bugs need to be fixed :-)</p>
    
  2. Matti Paksula Says:

    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.

  3. Simon B. Says:

    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?

  4. Simon B. Says:

    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?

  5. Dan Manges Says:

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

    <pre><code>sample = Class.new { include ModuleToTest }.new</code></pre>
    
  6. Michael Says:

    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?

  7. David Chelimsky Says:

    @Michael – actually, that’s a bug. For right now you’d be best just ignoring the warnings. I’ll get a fix in shortly.

  8. David Chelimsky Says:

    @Michael – fixed in a46a78d