RSpec与方法有关

时间:2010-04-19 20:58:06

标签: ruby-on-rails rspec mocking

我编写了以下规范:

  it "should call user.invite_friend" do

    user = mock_model(User, :id => 1)
    other_user = mock_model(User, :id => 2)
    User.stub!(:find).with(user.id).and_return(user)
    User.stub!(:find).with(other_user.id).and_return(other_user)
    user.should_receive(:invite_friend).with(other_user)

    post :invite, { :id => other_user.id }, {:user_id => user.id}

  end

但是当我运行规范

时,我收到以下错误
NoMethodError in 'UsersController POST invite should call user.invite_friend'
undefined method `find' for # Class:0x86d6918 
app/controllers/users_controller.rb:144:in `invite'
./spec/controllers/users_controller_spec.rb:13:

错误是什么?没有.with它工作得很好,但我想要对stub方法的不同参数有不同的返回值。以下控制器的操作可能是相关的:

  def invite
    me.invite_friend(User.find params[:id])
    respond_to do |format|
      format.html { redirect_to user_path(params[:id]) }
    end
  end
  def me
    User.find(session[:user_id])
  end

1 个答案:

答案 0 :(得分:1)

出现错误是因为第一次调用find时存根被“用完”了。第二个find没有存根,因此您得到NoM​​ethodError。

如果我错了,有人可以纠正我,但当你多次调用时,.with似乎对存根有一个奇怪的影响。 Rspec似乎将相同参数类型的每个消息与单个存根相关联。但另一种参数类型有效地创建了不同的存根。因此,在您的情况下,您可以通过使用字符串调用第二个find来修复它:

User.stub!(:find).with(other_user.id.to_s).and_return(other_user)

这对您来说很幸运,因为实际上控制器期望params哈希中的字符串。

这不能回答更大的问题:如何使用相同参数类型的参数存根多个方法调用?根据我的经验,你不能这样做。

当然,你可以通过不指定参数来绕过它。在您的情况下,我会说测试find本身与您的控制器无关 - 实际上,您正在测试ActiveRecord是否可以对主键进行数据库查找,主键已经过充分测试。因此,如果您只需要按正确的顺序将响应存根到find,那么您可以这样做:

User.stub!(:find).and_return(user,other_user)