测试使用after_create回调的模型规范

时间:2010-10-20 22:51:46

标签: unit-testing model rspec

这是我正在使用的模型,我将其简化为最简单的形式,但仍未通过我的示例:

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

我想将示例说明如下:

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

我期望它能正常工作,但我留下了以下错误:

Failures:
  1) User#setup_lists creates a new master list
     Failure/Error: List.should_receive(:create).with(:name => "current")
     (<List(id: integer, name: string, created_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

有人能帮我理解为什么会这样吗?

2 个答案:

答案 0 :(得分:4)

三个问题:

1)在设置消息期望之前创建User对象,因此should_receive永远不会看到消息;

2)你正在剔除你也在设定期望的方法。你想要找出你没有设定期望但是测试通过所需的方法

3)您需要传递所有参数

要修复,请在设置expectaion后创建User对象,并依次存根每个方法(因为模型调用List.create两次):

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

虽然它确实是一个风格问题,但是在这里使用真实的User对象而不是工厂更有意义,因为您正在测试模型本身。

答案 1 :(得分:2)

zetetic的答案很棒,但是如果你想要更快一点(并且仍然有效),我建议你使用shoulda-callback-matchers gem。它是一套完整的匹配器,可以更轻松地测试回调。我一切都很简单&amp;减少样板。如果您愿意,可以在我的RSpec model testing skeleton中查看一些示例。

无论哪种方式完成工作!