【问题标题】:How to mock chained associations in rails and rspec?如何在 Rails 和 rspec 中模拟链式关联?
【发布时间】:2012-07-19 11:48:27
【问题描述】:

在我的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)>'
     # '

此外,如果有人在 cmets 中删除有关 stub、mock 的详尽文章的好链接,我会非常高兴。仍然(显然)没有掌握这一点。

【问题讨论】:

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


    【解决方案1】:

    您在订阅上设置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

    【讨论】:

    • 这对我来说非常有效,非常感谢!我还尝试一次对链的多个属性进行存根,但没有奏效。您必须为每个属性声明一个单独的#stub_chain。这对某些人来说可能很明显,但它让我有一段时间感到困惑,所以我想我会分享。
    【解决方案2】:

    有几种方法可以做到这一点。如果你想要一个简单的解决方案,你可以使用 stub_chain 并传递任意数量的方法:

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

    还有一个是不直接使用活动记录,而是在用户模型上使用 finder 方法:

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

    这真的是一个意见问题,归结为你觉得最舒服的任何东西。我个人会选择选项一。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多