2015-04-19 48 views
1

我有一個singleton類可以被許多其他類和控制器訪問來確定行爲。如何在我的測試中設置單例值,以便測試行爲。示例代碼如下,其中Setting是Singleton類,由數據庫支持並存儲應用程序範圍的設置,這些設置可由管理員更改。 Floodgate是一個訪問設置的類。RSpec:如何存根方法和方法鏈

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

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

以下是需要訪問Settings數據庫值的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爲零。在Floodgate測試中,我如何設置它以保持它,atm在d/b中沒有記錄。我試着明確地將它設置爲如下,當我使用create時,錯誤響應是未定義的方法'create'。

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

回答

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 

後者去,如果你確定你是正確instanstiating Setting。順便說一下,配置相關的變量理想情況下會進入*.yml文件(例如database.yml要爲其使用數據庫),該文件將基於當前項目環境具有不同的值(在很多情況下,這會取消對存根方法的需要)。

+0

感謝您的評論。我通過將Singleton模型上的實例方法更改爲「first ||」來解決了我的問題new'。您的評論重新正確地實例化模型指出了我朝着正確的方向。 – margo