我有一个单例类,可以被许多其他类和控制器访问以确定行为。如何在我的测试中设置单例值,以便我可以测试行为。下面的示例代码,其中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 }
答案 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
,对于哪个数据库使用),根据当前项目环境会有不同的值(这将消除需求)在许多情况下,存根方法。