开发者

Testing a model spec that uses an after_create callback

Here is a model that I'm using, I've simplified it a bit down to the simplest form that still fails my example:

class User <  ActiveRecord::Base
  after_create :setup_lists

  def setup_lists
    List.create(:user_id => self.id, :name => "current")
    List.create(:user_id => self.id, :name => "master")
  end
end

And I'd like to spec the example as follows:

require 'spec_helper'

describe User do
  before(:each) do
    @user = Factory(:user)
  end

  describe "#setup_lists" do
    before(:each) do  
     List.stub(:create).with(:name => "current")
     List.stub(:create).with(:name => "master")

     it "creates a new master list" do
        List.should_receive(:create).with(:name => "master")
     end

     it "creates a new current list" do
        List.should_receive(:create).with(:name => "current")
     end
  end
end

Which I expected would work just fine, but I am left with the following error:

Failures:
  1) User#setup_lists creates a new master list
     Failure/Error: List.should_receive(:create).with(:name => "current")
     (<List(id: integer, name: string, cre开发者_如何转开发ated_at: datetime, updated_at: datetime, user_id: integer) (class)>).create({:name=>"current"})
      expected: 1 time
      received: 0 times
    # ./spec/models/user_spec.rb:44

  2) User#setup_lists creates a new current list
     Failure/Error: List.should_receive(:create).with(:name => "master")
     (<List(id: integer, name: string, created_at: datetime, updated_at: datetime,        user_id: integer) (class)>).create({:name=>"master"})
     expected: 1 time
     received: 0 times
  # ./spec/models/user_spec.rb:48

Can anybody help me understand why this is happening?


Three issues:

1) The User object is created before setting the message expectation, so should_receive never gets to see the message;

2) You're stubbing out methods for which you're also setting expectations. You want to stub out methods for which you don't set expectations, but which are needed for the test to pass

3) You need to pass in all the parameters

To fix, create the User object after setting the expectaion, and stub out each method in turn (because your model calls List.create twice):

describe User do
  describe "#setup_lists" do
    it "creates a new master list" do
      List.stub(:create).with(:user_id=>1,:name => "current")
      List.should_receive(:create).with(:user_id=>1,:name => "master")
      @user = User.create
    end

    it "creates a new current list" do
      List.stub(:create).with(:user_id=>1,:name => "master")
      List.should_receive(:create).with(:user_id=>1,:name => "current")
      @user = User.create
    end
  end
end

While it's really an issue of style, it makes more sense to use a real User object here rather than a factory, since you're testing the model itself.


zetetic's answer is awesome, but if you want something a bit quicker (and still works), I'd recommend using the shoulda-callback-matchers gem. It's a complete set of matchers that make testing callbacks easier. I'm all about easy & reducing boilerplate. You can see some examples in my RSpec model testing skeleton if you care to look.

Either way gets the job done!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜