使用Rspec should_receive来测试控制器正确调用对象上的方法

时间:2015-06-09 05:22:59

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

好的,首先,我应该说,虽然我已经阅读了很多关于should_receive的内容,但我仍然不能完全确定我理解它背后的概念,所以我&#39这样做可能完全不可能。

我有以下内容:

class PlansController
  def destroy
    plan = plan.find_by_id(params[:id])
    if plan.cancel_stripe_subscription(params[:reason])
      flash[:success] = "success"
      redirect_to root_path
    else
      #error handling
    end
  end
end

class Plan
  def cancel_stripe_subscription(reason)
    self.status = "canceled"
    self.cancellation_reason = reason
    if self.save
      return true
    else
      return false
    end
  end

在我的控制器规范中,我认为做一个成功调用cancel_stripe_subscription方法的测试(使用1should_receive1),使用正确的参数和所有内容,以及另一个测试输出{ {1}}行动是正确的。

换句话说,我想写下面的控制器规范:

destroy

第二次测试通过,但第一次测试

describe PlansController, "Destroy Action" do
  before do
    @plan = Plan.create(...)
  end
  it "should have called destroy action" do
    delete :destroy,
      plan: {
        id: @plan.id,
        reason: "something"
      }
      assigns(:plan).should_receive(:cancel_stripe_subscription).with(reason:"something").exactly(1).times.and_return(true)
  end

  it "should have called destroy action" do
    delete :destroy,
      plan: {
        id: @plan.id,
        reason: "something"
      }
    assigns(:plan).status.should == "canceled"
    assigns(:plan).cancellation_reason.should == "something"
  end
end

所以我真的有两个问题:

  1. 只是为了确认,我是否正确使用Failure/Error: assigns(:plan).should_receive(:cancel_stripe_subscription) (#<Plan:0x007fe282931310>).cancel_stripe_subscription(*(any args)) expected: 1 time with any arguments received: 0 times with any arguments ?我应该测试一下吗?或者第二次测试通常被认为是足够的?
  2. 如果我应该对此进行测试,那么使用should_receive的正确方法是什么? (注意,should_receive也没有好运)

2 个答案:

答案 0 :(得分:2)

我认为这里的困惑部分是由于结合了两种不同的测试方式,mockist(你的第一次测试)和classicist(你的第二次测试)。根据您偏好的测试方式使用其中一种,这很好,但是同时使用它们来测试同一段代码有点多余。

答案 1 :(得分:1)

在调用被测方法之前,必须设置<{1}}期望;你事后再设置它。由于您之前需要进行设置,因此必须确保您在操作中操作的对象已经设置好了。通常的方法是在should_receive上隐藏find_by_id,如下所示:

Plan

(我假设您打算在it "should have called destroy action" do Plan.stub(:find_by_id).and_return(@plan) assigns(:plan).should_receive(:cancel_stripe_subscription).with(reason:"something").exactly(1).times.and_return(true) delete :destroy, plan: { id: @plan.id, reason: "something" } end 行动的第一行写下plan = Plan.find_by_id(params[:id])。)

至于你是否应该以这种方式进行测试,我说你的第二次测试能够很好地验证你想要的结果,而且你没有&#39;真的需要解决所有麻烦。