Rspec'ing Model Associations

Posted on February 27, 2007

How do you go about spec’ing model associations?

There’s an idea on the rspec mailing list.

However, I kind of like using reflect_on_association. Let’s say we have the following model:

class Product < ActiveRecord::Base

  has_and_belongs_to_many :categories
  has_many :images
  has_many :inventories
  belongs_to :designer

end

Then my context and specifications might look like:

context "Product model" do

  specify "should respond to inventories" do
    Product.reflect_on_association(:inventories).should_not_be_nil
  end

  specify "should respond to categories" do
    Product.reflect_on_association(:categories).should_not_be_nil
  end

  specify "should respond to images" do
    Product.reflect_on_association(:images).should_not_be_nil
  end

  specify "should respond to designer" do
    Product.reflect_on_association(:designer).should_not_be_nil
  end
end

This will catch the situation where an association definition is removed or changed.

Rspec'ing Rails Controllers

Posted on February 26, 2007

I’ve been using rspec for a few months now, and I really like it. I recommend trying it out if you haven’t.

I figure it might be nice to share how I organize controller specs, and get some feedback on how others might organize their specs. I like having one test per specification like so:

specify "should redirect to new session url" do
   response.should_redirect_to new_session_url
end

I also like calling the controller action in the setup method.

setup do
   ... any necessary setup info
   post :update, :id => model, :model => params
end

Here’s what a context might look like in all its glory.

context "Create with a valid product and authenticated user" do
  include ProductsControllerSpecHelper
  controller_name :products

  setup do
    @product = mock(:product, :null_object => true)
    Product.stub!(:new).and_return(@product)
    @product.should_receive(:save!).and_return(true)
    @product.should_receive(:categories).and_return([])
    authenticate_user_mock

    post :create, :product => valid_product_attributes

  end

  specify "should redirect to edit" do
    response.should_redirect_to edit_product_url(@product)
  end

  specify "should assign product" do
    assigns[:product].should_not_be_nil
  end

end

Rspec'ing Rails Views

Posted on February 12, 2007

I've been using rspec for testing rails apps for about a month now. However, I hadn't tried to spec out the views. I decided to starting specing out the views today, and ran into a small obstacle.

I am currently using restful authentication plugin and I have snippets in my view like:


    <% if logged_in? %>
         ....
    <% end %>

Everything is good, until I tried to write my first view test. Calling:

render "controller/template"

I received a missing method error on "logged_in?". The problem is that rspec views are tested in isolation from the controller. This means my include AuthenticatedSystem in the application controller doesn't get loaded and that's where the "logged_in?" method is mixed in.

I did find out that the application_helper.rb and <controller>_helper.rb (where <controller> is the current controller associated with the template being tested) get loaded, so I could define the "logged_in?" method in either of the two helper classes. But the problem with that is that I would have "logged_in?" defined in a couple of places just to run my rspecs.

Digging around in the rspec for rails code base, I found that you can get access to the controller via @controller and the template via @controller.template.

Then a light came on! I could stub out the call to logged_in? on the template like so:

   @controller.template.stub!(:logged_in?).and_return(true)

After doing that, everything worked fine. I also found it came in handy for stubbing out other template calls.