[rspec-users] Refactoring and using each

Nick Hoffman nick at deadorange.com
Thu Oct 9 15:27:07 EDT 2008


On 2008-10-08, at 07:01, Jeroen van Dijk wrote:
> Hi all,
>
> I'm new to this list and new to RSpec so I have been trying out  
> RSpec the last couple of days and I find it very a natural way of  
> testing. So first of all thanks for providing this framework.
>
> Now, I have written some tests for my controllers and models and I  
> saw myself writing similar code, so I began refactoring and came up  
> with the following issue.
>
> Here is a simple example of what I first wrote:
>
> describe Example do
>
>   it "should not be valid without attribute1" do
>     Example.new(:attribute2 => "2").should_not be_valid
>   end
>
>   it "should not be valid without attribute2" do
>     Example.new(:attribute1 => "1").should_not be_valid
>   end
> end
>
> Which I rewrote into another working test:
>
> ######
> module ExampleSpecHelper
>   def required_valid_attributes
>     {:attribute1 => "1", :attribute2 => "2"}
>   end
> end
>
> describe Example do
>    include ExampleSpecHelper
>   [:attribute1, :attribute2].each do |attribute|
>   before(:all) do
>     @model_with_one_missing_attribute =  
> TextMessage.new(required_valid_attributes.except(attribute))
>   end
>
>   it "should not be valid without #{attribute}" do
>     @model_with_one_missing_attribute.should_not be_valid
>   end
> end
> #####
>
> In this example in you might not see difference in lines of code,  
> but imagine you would have 10 attributes and 10 more tests for each  
> attribute.. Now I rewrote this I was still not satisfied because I  
> thought I would like to use this same  approach for several models  
> with different attributes while keeping the logic of this test in  
> one place. Unfortunately, I didn't come that far because of this:
>
> #this works:
> describe Example do
> include ExampleSpecHelper
>   required_attributes = [:attribute1, :attribute2]
>   required_attributes.each do |attribute|
>   before(:all) do
>     @model_with_one_missing_attribute =  
> TextMessage.new(required_valid_attributes.except(attribute))
>   end
>
>   it "should not be valid without #{attribute}" do
>     @model_with_one_missing_attribute.should_not be_valid
>   end
> end
>
> #However this which eventually will be more DRY, but does for some  
> reason not work?!
> module ExampleSpecHelper
>   ...
>   def required_attributes
>     [:attribute1, :attribute2]
>   end
> ...
> end
>
> describe Example do
> include ExampleSpecHelper
>   required_attributes.each do |attribute|
>   before(:all) do
>     @model_with_one_missing_attribute =  
> TextMessage.new(required_valid_attributes.except(attribute))
>   end
>
>   it "should not be valid without #{attribute}" do
>     @model_with_one_missing_attribute.should_not be_valid
>   end
> end
>
>
> ############
>
> I don't understand why it does not work. In the last example  
> required_attributes is nil while the other methods from the helper  
> module such as 'required_valid_attributes' are available on an even  
> lower level. Why? I hope you understand why I'm trying to refactor  
> it like this. If I can do this I only need to define the required  
> attributes for each model and use it_should_behave_like "an AR  
> model" to keep it DRY.
>
> Hope someone can clarify this and that I haven't done something  
> stupid! Thanks!
>
> Cheers,
>
> Jeroen

Hi Jeroen. As I was getting into RSpec and writing specs for my  
various models, I too found that my code could be a lot DRYer. I ended  
up writing a module that generates specs for my model attributes. I've  
put it up on GitHub, along with full, lengthy example of how to use  
it. Have a look:
   http://github.com/nickhoffman/modelspeccer/

Cheers,
Nick


More information about the rspec-users mailing list