RSpec测试控制器实例变量接收消息

时间:2017-01-19 06:20:47

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

我知道控制器规范中的expect(assign(:var))测试@var被分配给某个值。在我的情况下,我想测试此@var是否收到特定消息。如果我在get :action之前执行此操作,则分配返回nil。如果我之后这样做,那么期待这条消息为时已晚。

# controller
def action
  @var = something
  @var.message
  render :nothing
end

# spec1
expect(assigns(:var)).to receive(:message) # not working, var is nil
get :action

# spec2
get :action
expect(assigns(:var)).to receive(:message) # not working, expectation too late

3 个答案:

答案 0 :(得分:2)

你在这里看的是测试双打或嘲笑。您可以通过添加rspec-mocks gem或其他测试双宝石来使用它们,例如RR

一旦你有其中一个(我个人使用RR),你可以这样做(RR的语法):

mock(assigns(:var)).foo
get :action

rspec-mocks的语法不是100%肯定,但它看起来应该是这样的:

var = double(assigns(:var))
expect(var).to receive(:foo)
get :action

如果您需要添加更多支票,则应查看Message ExpectationsExpecting Arguments的自述文件。

答案 1 :(得分:0)

由于变量在控制器中以相同的方法分配和调用,我不相信你有办法在它之间捕获并模拟它。

相反,我通常期望“any_instance_of”像这样:

expect_any_instance_of(ClassOfVar).to receive(:message)

答案 2 :(得分:0)

我目前正在强制控制器实例变量以期望消息开启。虽然这有效,但它会跳过加载逻辑(cancan),所以我为此创建了另一个测试:

  it "loads and authorizes object" do
    get :action, id: 10
    assert_response :success
  end

  it "calls action on object" do
    controller.instance_variable_set('@var', @my_real_object_or_mock_here)
    expect(@my_real_object_or_mock_here).to receive(:message)
    get :action, id: 10
    assert_response :success
  end

我有点觉得这个解决方案很苛刻,但如果这个答案获得最多的选票,我会接受它:)