RSpec:如何存根方法和方法链

时间:2015-04-19 09:38:00

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

我有一个单例类,可以被许多其他类和控制器访问以确定行为。如何在我的测试中设置单例值,以便我可以测试行为。下面的示例代码,其中Setting是Singleton类,由数据库支持并存储应用程序范围的设置,管理员可以更改这些设置。 Floodgate是一个访问设置的类。

class Setting
  def instance
    @setting ||= new
  end
end

class Floodgate
  def self.whitelist
    Setting.instance.flood_gate_whitelist
  end
end

以下是一些需要访问“设置”数据库值的Floodgate测试。

describe Floodgate do
  let(:setting) { Class.create(Setting).instance }

describe ".whitelist" do
  it "returns a list of values on the Settings floodgate whitelist" do
    expect(Floodgate.whitelist).to eq 'google'
  end
end

describe ".allow_traffic_source?" do
  it "returns true if traffic source is on the white list" do
    expect(Floodgate.allow_traffic_source?('google')).to eq true
  end

  it "returns false if traffic source is not on the white list" do
    expect(Floodgate.allow_traffic_source?('facebook')).to eq false
  end
end

上面的第一个和第二个测试失败,因为Setting.flood_gate_whitelist是nil。在Floodgate测试中,如何设置它以使其持续存在,因为d / b中没有记录。我尝试显式设置如下,当我使用create时,错误响应是未定义的方法'create'。

let(:setting) { Class.new(Setting, flood_gate_whitelist: 'google').instance } 

1 个答案:

答案 0 :(得分:3)

将正在调用的消息链存根。在您的情况下,一个例子是:

before do
  allow(Setting).
    to receive_message_chain("instance.flood_gate_whitelist").
      and_return("google")
end

现在代码中的任何位置Setting.instance.flood_gate_whitelist都会返回"google"

或者,您可以在Setting上存储实例方法,如下所示:

before do
  allow_any_instance_of(Setting).
    to receive(:flood_gate_whitelist).
      and_return("google")
end

如果您确定正确显示Setting,请使用后者。

顺便提一下,与配置相关的变量理想情况下会进入*.yml文件(例如database.yml,对于哪个数据库使用),根据当前项目环境会有不同的值(这将消除需求)在许多情况下,存根方法。