如何在存根时访问对象的实例变量?

How to access an object's instance variables while stubbing?

我正在为 Web 应用程序编写一些测试,其中一个控制器在 Scope 对象上调用 resolve,return 是一个略微修改的范围。在测试中,我想将此方法存根到 return 原始范围(作为参数传递给 Scope.initialize)。

Scope对象

class Scope

  def initialize(scope)
    @scope = scope
  end

  def resolve
    # Return a modified scope.
  end
end

控制器

class FooController < ApplicationController

  def show
    foos = Scope.new(Foo.some_foos).resolve
    respond_with foos
  end
end

测试

it "does something" do
  allow_any_instance_of(Scope).to receive(:resolve).and_return(???.scope)
  get :show
  # Do some assertions.
end

我需要在 ??? 所在的位置放置什么,以便将 Scope 的任何实例上的 resolve 方法存根到 return 它所在的原始范围是用什么创建的?

我正在使用 Rspec 3.4.2.

首先,您需要在 Scope 上创建一个属性 reader,这样您就可以在不使用 instance_variable_get 的情况下访问 @scope:

class Scope

  attr_reader :scope

  def initialize(scope)
    @scope = scope
  end

  def resolve
    # Return a modified scope.
  end
end

如果您使用块实现,则接收器作为第一个参数传递:

allow_any_instance_of(Scope).to receive(:resolve) do |s|
  s.scope
end

然而,强烈建议不要使用 allow_any_instance_of,这通常表明您的测试过于关注控制器的工作方式,而不是实际 testing their behavior in a future proof way

我会改为使用测试 Scope 的单元测试,并请求结合功能规范测试控制器的规范。这就是我测试使用 Pundit 的应用程序的方式,是一种可靠的策略。