rspec-1.1.12 is released

January 13th, 2009

We just released rspec-1.1.12. You can read the changelogs for rspec and rspec-rails for all the details, but are some changes that you should definitely know about.

Cucumber is the new Story Runner

rspec-1.1.12 is the last release that will ship with the Story Runner bundled. With the next release, we will do the one and only gem release of repo so you won’t be forced to upgrade to Cucumber Thanks to Chad Humphries for stepping in and extracting the Story Runner to a separate repo.

The Story Runner is deprecated, however, and we will not be maintaining it. If anybody wants to maintain it, you’re welcome to. Just fork the repo and have at it.

Why are we deprecating the Story Runner? Because Aslak Hellesøy’s Cucumber library kicks its ass. Easier setup means lower barrier to entry, building on treetop means great feedback with backtraces plus support for an ever-growing list of written languages. And migrating from RSpec Stories is a snap. So what are you waiting for?

### Rails 1.2.6 will no longer be supported by new versions of rspec

rspec-rails-1.1.12 is the last rspec release that will support pre-2.0 releases of Rails. For anybody interested in maintaining rspec-rails for rails-1.2.6, I’ve created a 1.1-maintenance branch, which you are welcome to fork and go nuts. There is also a 1.1-maintenance branch for rspec, so you’d be working from a matched pair.

So that’s what’s going away. Here’s what’s new!

it { should provide_an_implicit_subject }

Ever write a code example like this?

1
2
3
4
5
6
7
describe Person do
  it "should validate presence of email" do
    person = Person.new(:email =>; nil)
    person.should_not be_valid
    person.should have(1).error_on(:email)
  end
end

That comes up pretty often in rails apps when spec’ing out models. There are a few matcher libraries out there like rspec-on-rails-matchers that provide matchers like this validate_presence_of(:email), which let you reduce the previous example to this:

1
2
3
4
5
describe Person do
  it "should validate presence email" do
    Person.new.should validate_presence_of(:email)
  end
end

Of course, the next step is to want to get rid of the redundancy between the docstring passed to #it and the matcher, so you end up with this:

1
2
3
4
5
describe Person do
  it do
    Person.new.should validate_presence_of(:email)
  end
end

Do it? Ugh! This has always driven me nuts when I see it do, so I’d make that this:

1
2
3
describe Person do
  it { Person.new.should validate_presence_of(:email) }
end

Well, thanks to a contribution from Joe Ferris from thoughtbot, we now have an implicit subject in our specs, so you can do this:

1
2
3
describe Person do
  it { should validate_presence_of(:email) }
end

w00t! Now that is concise. Brandon Keepers wrote about this a while back, but this feature hadn’t actually been released until rspec-1.1.12.

it { should handle_slightly_more_complex_conditions }

The implicit subject feature works by creating a new instance of the class passed to describe for each example. In the last example above, when the example receives the #should message, it delegates it to a new instance of Person. That’s fine for a lot of cases, but sometimes we’ll need a bit more context than simply calling new. For those situations, you can create your own subject for an example group like this:

1
2
3
4
5
6
7
8
describe Person do
  describe "born 19 years ago" do
    subject { Person.new(:birthdate => 19.years.ago }
    it { should be_eligible_to_vote }
    it { should be_eligible_to_enlist }
    it { should_not be_eligible_to_drink }
  end
end

Happy Spec’ing, and Happy New Year!

25 Responses to “rspec-1.1.12 is released”

  1. Greg Says:

    I like this implicit subject feature quite a bit. Is there any easy way to specify results of methods called on the object using this syntax? i.e. any way to translate:

    it "should have a default name" do
      @foo.name.should eql("bar")
    end
    

    into the new syntax? In going through the existing specs for my current project, I find a number of situations like this.

  2. David Chelimsky Says:

    @Greg: you could write custom matchers to support:

    describe Thing do
      it { should have_default_name_of("bar") }
    end
    

    … or perhaps:

    describe Thing do
      it { should default_to(:name => "bar") }
    end
    

    The first one would look like this:

    def have_default_name_of(name)
      simple_matcher do |actual, matcher|
        matcher.failure_message = "expected default name of #{name}"
        actual.name == name
      end
    end
    

  3. Greg Says:

    Thanks. I ended up writing something more generic (using method_missing) to test the value of any attribute (or any method with no arguments, really).

    <p><code>it { should return_the_name("bar") }</code></p>
    
    
    <p>I&#8217;m not entirely happy with the &#8220;return_the&#8221; prefix, so any other suggestions would be appreciated. :)  ( I originally thought &#8220;have_the&#8221; would work, but that interferes with the existing has matcher)</p>
    
  4. David Chelimsky Says:

    How about:

    it { should be_named("bar") }
    

    You should be able to define be_xxx or have_xxx without interfering with the Be or Has matchers – those are only invoked via method_missing.

  5. Greg Says:

    Mine uses method_missing too, though – so return_the_sym(arg) verifies that subject.send(sym) == arg. That seemed more expedient than writing a custom matcher for every attribute I wanted to test in this manner, although there are always tradeoffs to using method_missing, of course.

  6. Cássio Marques Says:

    David,

    <p>After upgrading to 1.1.12 I&#8217;m getting the following warning in my view specs</p>
    
    
    <p>[](name) as an alias for capture(name) (TestResponse extension in rspec-rails)
    

    is deprecated and will be removed in the rspec-rails release that follows the rails-2.3.0 release.

    <p>What does that means?</p>
    
    
    <p>Thanks!</p>
    
  7. Jim Gay Says:

    David,

    <p>What do you think about creating an alias for &#8216;it&#8217; with &#8216;the&#8217;?</p>
    
    
    <p>This (for me, in this scenario) would make sense</p>
    

    the { root_path.should == '/welcome' }
    

    My relevant ticket is here: http://rspec.lighthouseapp.com/projects/5645/tickets/646-feature-request-test-named-routes-in-rails-controller-examples#ticket-646-1

  8. Craig Buchek Says:

    +1 for Jim Gay’s suggestion.

  9. Cássio Marques Says:

    Nevermind David, found your commit message at GitHub and fixed my specs. Thanks!

  10. Sébastien Grosjean - ZenCocoon Says:

    Hi,

    <p>Such nice release, that makes testing much more sexy ;-) 

    Thanks for making testing more enjoyable.

    <p>Quick question, obj.stub!(:msg) being now deprecated, how could I replace it ?
    

    This actually comes from http://github.com/joshknowles/rspec-on-rails-matchers/tree/master ’s validate_uniqueness_of

    <p>Thanks again,</p>
    
  11. David Chelimsky Says:

    Jim, Craig – I’d be adverse to adding another keyword like “the”, but we’ve seen requests for other keywords before. Maybe what we need is a way to declare your own keywords for creating examples and/or example groups. Then you’d be able to do something like this:

    Spec::Example.keywords_for :example { :the }
    

    WDYT?

  12. David Chelimsky Says:

    Sébastien, obj.stub(:msg) is not deprecated. Where did you get the idea that it is?

  13. Sébastien Grosjean - ZenCocoon Says:

    David, I understood that from http://rspec.info/documentation/changes-rspec.html but as not natural English speakers I might just have understood wrong.

    <p>Would be glad to get things clarified ;-) 

    Warm regards,

  14. Jim Gay Says:

    Something like keywords_for sounds like a good idea. I agree that another keyword could be unnecessary bloat.

  15. David Chelimsky Says:

    Sébastien – none of that is deprecated. There was a bug that allowed you to write passing examples that should fail. Please take a look at the bug report and see if the information there clarifies things for you.

  16. Sébastien Grosjean - ZenCocoon Says:

    David, Ok got it, thanks a lot for the details, that makes all clear now.

    <p>Thanks again for your great work,</p>
    
  17. Stephen Touset Says:

    On all examples with an implicit subject, I now get a huge failure message essentially saying that the matcher doesn’t have a defined #description. I originally thought this was an issue with only my custom matchers (it wasn’t, they had it defined), but then I found that it also prints that for failures on builtins like “it { should be_blank }”.

  18. Stephen Touset Says:

    Also, with regard to testing an implicit object’s accessors, what about:

    <pre><code><code>its(:foo) { should be_nil }</code></code></pre>
    
  19. Stephen Touset Says:

    [code] def self.its(attribute, &block) describe(@attribute) do define_method(:subject) { super.send(attribute) } it(&block) end end [/code]

  20. Stephen Touset Says:

    Dammit.

    def self.its(attribute, &block) describe(@attribute) do define_method(:subject) { super.send(attribute) } it(&block) end end

  21. Stephen Touset Says:

    For god’s sake.

    
    def self.its(attribute, &block)
      describe(@attribute) do
        define_method(:subject) { super.send(attribute) }
        it(&block)
      end
    end
    

  22. Wincent Colaiuta Says:

    The implicit subjects are certainly sexy but I don’t think I’ll be using them.

    <p>They certainly <em>read</em> very nicely (&#8220;it should validate presence of email&#8221;) but literally all of the actual code has now been replaced with magic. I don&#8217;t think that reading like an English sentence should be the ultimate goal here.</p>
    
    
    <p>Somebody not familiar with RSpec can no longer look at it and know what&#8217;s actually being tested. What object is being tested? How is it created? How is the validation confirmed?</p>
    
    
    <p>The old way is explicit rather than <span class="caps">DRY</span> and I very much prefer it. Of course there still is magic there too, but much less.</p>
    
  23. rubyruy Says:

    For better or for worse, if you’re using RSpec you’re already neck-deep in magic-land. It’s kind of a forgone conclusion that people unfamiliar with it are going to confused.

  24. Ben Wagaman Says:

    Stephen, I like your idea. I think you mean describe(attribute), instead of describe(@attribute) though so that the attribute is put into the output of the spec.

    <p>Where would this method get inserted if it were included in rspec or put in to a plugin?</p>
    
  25. Craig Buchek Says:

    Stephen Touset’s implementation of its() looks like it’ll do in place of Jim Gay’s suggestion of implementing the(). It doesn’t read quite as nicely, but it’s close. And it has the advantage of putting the attribute name more in focus.

    <p>I&#8217;d really like to see one or the other added to RSpec.</p>