如何在rails和rspec中模拟链式关联?

时间:2012-07-19 11:48:28

标签: ruby-on-rails rspec2 rspec-rails

SubscriptionsController我有:

  # DELETE /subscription # {{{
  def destroy
    @subscription = current_user.subscriptions.find params[:id]
    @subscription.cancel!
    redirect_to subscriptions_path, :notice => "Abonnement beendet." 
  end# }}}

在我的Controller-Specs中模拟current_user.subscriptions.find params[:id]的正确方法是什么?

目前我正在尝试使用我之前的版块。

  double(Subscription)
  controller.current_user.stub!(:subscriptions).and_return(Subscription)
  Subscription.stub!(:find).and_return(subscription)

但这似乎没有按预期工作,因为我的RSpec-Expectations不起作用。

it "updates the status to canceled" do
  sub = Subscription.stub!(:find).and_return(subscription)
  sub.stub!(:cancel!)
  sub.should_receive :cancel!
  delete :destroy, :id => 1
end

此块总是失败,因为should_receive期望未得到满足:

1) SubscriptionsController DELETE /subscription/:id updates the status to canceled
  Failure/Error: sub.should_receive :cancel!
    (#<Proc:0x007fbdec0a2650@/Users/nilsriedemann/.rvm/gems/ruby-1.9.3-p125-perf@bloomy-days/gems/rspec-mocks-2.6.0/lib/rspec/mocks/message_expectation.rb:63 (lambda)>).cancel!(any args)
     expected: 1 time
     received: 0 times
     # ./spec/controllers/subscriptions_controller_spec.rb:38:in
     # `block (3 levels) in <top (required)>'
     # '

此外,如果有人在评论中删除关于存根,嘲笑的完整文章的链接,我会非常高兴。仍然(显然)没有掌握这一点。

2 个答案:

答案 0 :(得分:4)

您在订阅上设置should_receive,而不是find将返回的对象。

这样的东西
Subscription.stub!(:find).and_return(subscription)
subscription.should_receive :cancel!

就是你所追求的。

您可能也对stub_chain

感兴趣
some_user.stub_chain(:subscriptions, :find => some_result)

设置以便

some_user.subscriptions.find 

返回some_result

答案 1 :(得分:1)

有几种方法可以做到这一点。如果您想要一个简单的解决方案,可以使用stub_chain并根据需要传递多个方法:

let(:subscription) { mock(:subscription) }
current_user.stub_chain(:subscriptions, :find) { subscription }

而另一种方法是不直接使用活动记录并在用户模型上使用finder方法:

let(:subscription) { mock(:subscription) }
current_user.stub(:find_subscription) { subscription }

这真的是一个意见问题,归结为你感到最舒服的事情。我个人会选择一个。