【问题标题】:RSpec testing a controller instance variable receives a messageRSpec 测试控制器实例变量接收到消息
【发布时间】:2017-01-19 06:20:47
【问题描述】:

我知道控制器规格中的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

【问题讨论】:

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


    【解决方案1】:

    您在此处查看的是测试替身或模拟。您可以通过添加 rspec-mocks gem 或另一个测试双 gem(如 RR)来使用它们。

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

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

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

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

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

    【讨论】:

    • 尝试使用 rspec-mocks 但它不起作用,或者我无法弄清楚它应该如何编写:var = spy(assigns(:var), action: 1); get :action, id: 10; expect(var).to have_received(:action)
    • 不幸的是,assigns(:var) 如果在get :action 之前调用,将返回nil,这就是我问题的重点。为此,我尝试了spy 而不是double,这也不起作用。
    • 也许试试@var 而不是assigns(:var)
    • @var 指向不在控制器范围内的规范示例中的实例变量
    【解决方案2】:

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

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

    expect_any_instance_of(ClassOfVar).to receive(:message)
    

    【讨论】:

    • 虽然期望任何实例都可以工作,但假设任何实例都可以接收到消息并且测试会通过是不安全的。
    • 我同意它不会在所有情况下都有效,并且它并不完美,但它适用于大多数情况,它是您所描述问题的唯一解决方案,即我知道:-)我很高兴看到其他人是否可以完美解决您的问题而没有缺点,但目前这是我能想到的最好的:-)
    【解决方案3】:

    我目前正在强制控制器实例变量期待消息。虽然这可行,但它跳过了加载逻辑(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
    

    我觉得这个解决方案有点骇人听闻,但如果这个答案获得最多票,我会接受它:)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-22
      • 2021-11-25
      • 1970-01-01
      相关资源
      最近更新 更多