Prior to the introduction of nested example groups in RSpec, I'd always felt that descriptions got a little unwieldy when trying to describe the different cases and disliked specifying the controller_name repeatedly. For example (and these are real examples from real projects at work, with actual code removed for conciseness):

describe 'POST HotelDealsController#create with a valid hotel deal' do
  controller_name :hotel_deals

  before(:each) do
    # ...
  end

  it "should create and save a new hotel deal" do
    # ...
  end
end

describe 'POST HotelDealsController#create with an invalid hotel deal' do
  controller_name :hotel_deals

  before(:each) do
    # ...
  end

  it "should not perform any redirection" do
    # ...
  end
end

Nested example groups allow me to do this instead:

describe SearchController do
  before(:each) do
    @search = mock_model(Search)
  end

  describe "POST 'create'" do

    it "should render 'new' when creating an invalid search" do
      # ...
    end

    describe "with a valid search that has a location_id" do
      before(:each) do
        @search.stub!(:valid?).and_return(true)
        @search.stub!(:location_id).and_return(1)
      end

      it "should save a new search that has a location_id, location_code and location_name, and redirect to 'show'" do
        # ...
      end
    end

    describe "with a valid search that doesn't have a location_id" do
      before(:each) do
        @search.stub!(:valid?).and_return(true)
        @search.stub!(:location_id).and_return(nil)
      end

      it "should ask the Location model for possible locations if the search doesn't have a location_id" do
        # ...
      end
    end
  end
end

What's the difference you say? Well, while it may sound trivial, I can do describe SearchController only once and nest all examples for the different actions and scenarios inside without breaking it up into separate top-level example groups where I'd need to say controller_name :search multiple times.

Another (more important) benefit is I can progessively specify different scenarios I want to test by nesting them and providing a before block to setup mocks and stubs for that specific scenario. Let's look at what I mean with some code. Over here, I'm specifying the create action of my SearchController:


describe "POST 'create'" do
  it "should render 'new' when creating an invalid search" do
    # ...
  end

  describe "with a valid search that has a location_id" do
    # ...
  end

  describe "with a valid search that doesn't have a location_id" do
    # ...
  end
end

There're 3 possible scenarios here: an invalid search, a valid search with a location_id, and a valid search without an location_id. I can write examples for invalid searches within the top-level example group itself (it "should render 'new' when creating an invalid search"). Now, to test valid searches, I break out 2 nested example groups with their own before block to setup mock searches, one which has a location_id, the other doesn't. What's the big deal? It just feels much more organized than the first, non-nested example where a top-level example group is created for each scenario.

And I know it may not seem like much, and I don't think there's anything particularly wrong with non-nested examples - it's a matter of personal preference. Nesting allows me to write examples for controllers in a saner fashion where I can say confidently to myself that "all examples for XXX action go here". I'm a big believer in readable tests (if you're on the Rails Trac much and have seen my reviews and patches you should know), so being able to write specs where I feel they belong makes me happier, and the examples read really nicely too.

I guess what I'm really trying to say is this: when trying to add a new example to legacy specs (legacy being anything that was written more than 5 mins ago) I instantly know where to place it - gone are the days of going through different example groups looking for the right place to put my new specification (and often settling on just simply creating a new top-level example group). I like to think we've all been there.

That said, I'm not saying that deeply nested examples are a good thing. When testing Rails controllers I find that you don't often have to go more than 3 deep to allow for all the possible scenarios. Any more would suggest that your controller is doing too much work.