views:

62

answers:

2

I'm trying to write a functional test. My test looks as following:

describe PostsController do
  it "should create a Post" do
    Post.should_receive(:new).once
    post :create, { :post => { :caption => "ThePost", :category => "MyCategory" } }
  end
end

My PostsController (a part of it actually) looks as following:

PostController < ActiveRecord::Base

  def create
    @post = Post.new(params[:post])
  end

end

Running the test I'm always receiving a failure, which says that the Post class expected :new but never got it. Still, the actual post is created.

I'm a newbie to RSpec. Am I missing something?

A: 

You can use the controller method of Rspec-rails to test message expectations on controllers, as described here. So one way of testing your create action is like so:

describe PostsController do
  it "should create a Post" do
    controller.should_receive(:create).once
    post :create, { :post => { :caption => "ThePost", :category => "MyCategory" } }
  end
end

EDIT (making an argument)

You might want to consider whether it's a good idea to write a test that depends on the implementation of the create action. If you're testing for anything other than the proper responsibilities of a controller, you run the risk of breaking tests when refactoring, and having to go back and rewrites tests when the implementation changes.

The job of the create action is to create something -- so test for that:

Post.count.should == 1

and then you know whether a Post was created, without depending on how it was created.

EDIT #2 (um...)

I see from your original question that you already know the Post is being created. I'd still argue that you should test for behavior, not implementation, and that checking for whether the model receives a message is not a good thing in a controller test. Maybe what you're doing is debugging, not testing?

zetetic
Thanks, but that's not the something I'm trying to accomplish. What I want to do is to check if a model class received a certain message (like :find, :create or so)
gmile
A: 

EDIT - Threw away the previous rubbish

This should do what you want

require File.dirname(__FILE__) + '/../spec_helper'

describe PostsController do
  it "should create a Post" do
    attributes = {"Category" => "MyCategory", "caption" => "ThePost"}
    Post.stub!(:new).and_return(@post = mock_model(Post, :save => false))
    Post.should_receive(:new).with( attributes ).and_return @post
    post :create, { :post => attributes }
  end
end

This assumes you are using rspecs own mocking library and that you have the rspec_rails gem installed.

Steve Weet