On May 13, 2010, at 6:41 AM, Ants Pants wrote:

> Hello everyone,
> 
> I'm just working my way through the RSpec/Cucumber book, I love the tool but 
> not so much the learning curve :(

Welcome! We're here to help.

> Starting with my first view, is it okay for me, in the BDD world, to do the 
> following or can I put them all in one 'it' block to save on having to render 
> the page every time. Or must they be in separate blocks with separate 
> renders? Or is there a fourth more elegant solution?
> 
>   %w{ name address_1 address_2 address_3 postcode town_city state country 
> email phone www }.each do |field|
>     it "renders form field #{field} to create a new competition" do
>       @competition.stub!(field.intern).and_return ''
>       render "competitions/new.html.erb"
>       response.should have_selector("input[type=text]", :name => 
> "competition[#{field}]", :value => '') 
>     end
>   end
> 
> Is it okay to post this type of  question if nothing jumps out at me after 
> googling?

Yes! And thanks for googling first.

There is a guideline that comes from TDD that there should be one expectation 
per example. This is not a law, and is not necessarily the best way to go every 
time. One benefit is that it's easier to read the examples and understand what 
they're specifying. Another is that when we make a change in the implementation 
that results in an example failing, if there are multiple expectations that 
should fail, we learn more if they're all in separate examples than if they're 
all piled up in one example. 

In terms of iterating through a list of fields, I personally do it all the time 
and it rarely causes any pain _as long as it is only one level deep_. If you 
start nesting these, you're in for a world of pain when new requirements come 
in that point to a change in behaviour, because you have to start teasing 
things apart.

Another approach to the same issue would be a custom matcher:

Rspec::Matchers.define :have_text_field_named do |name|
  match do |response|
    response.should have_selector("input[type=text]", :name => 
"competition[#{name}]", :value => '')
  end

  failure_message_for_should do |response|
    "expected text field named #{name}, got:\n#{response.body.inspect}"
  end
end

Now you can say:

describe "competitions/new.html.erb" do

  describe "form fields" do
    before(:each) do
      assigns[:competition] = double('competition').as_null_object
    end

    %w[name address_1 address_2 address_3 postcode town_city state country 
email phone www].each do |field|
      it "renders a #{field} field to create a new competition" do
        render
        response.should have_text_field_named(field)
      end
    end

  end
end

Notes:

- using as_null_object means you don't have to stub out the methods on the 
competition
- if you pass the path to the template file as the first argument to the 
outermost call to describe(), render() will render it implicitly, so it doesn't 
need to be in the example as well.
- code in the example is now focused on what is unique to that example
- I prefer to use %w[] over %w{} because it creates an array, not a hash or a 
lambda :)

All of this said, there is a general trend away from view specs in light of the 
Cucumber + (Webrat || Capybara) equation. My personal feeling is that it's 
important to know how to use them because they are very useful from time to 
time. But that's only one opinion.

HTH,
David

> Thanks
> 
> ants


_______________________________________________
rspec-users mailing list
rspec-users@rubyforge.org
http://rubyforge.org/mailman/listinfo/rspec-users

Reply via email to