2014-03-28 96 views
0

我已經寫下了服務對象。如何測試服務對象

class LeadGeneration 
    def initialize contact_id 
    @lead = Lead.find_or_initialize_by(contact_id: contact_id) 
    end 

    def lead 
    @lead 
    end 

    def activate_lead 
    lead.active! 
    end 

    def stale_lead 
    lead.stale! 
    end 
end 

我對如何測試它有點困惑。我寫了下面的規格

require 'spec_helper' 

describe LeadGeneration do 
    let(:contact) { FactoryGirl.create(:contact) } 

it "#activate_lead" do 
    lg = LeadGeneration.new(contact.id) 
    expect(lg.lead).to receive(:active!) 
    lg.activate_lead 
    end 

    it "#stale_lead" do 
    lg = LeadGeneration.new(contact.id) 
    expect(lg.lead).to receive(:stale!) 
    lg.stale_lead 
    end 
end 

該規範工作正常,但我想這樣做而不暴露生成的鉛。我究竟如何去做這件事。我可以使用

expect(Lead.any_instance).to receive(:active!) 

但是從我的閱讀中,這是不好的做法。有什麼想法嗎?

+0

你是什麼意思:「這個規範工作正常,但我想這樣做**而不會暴露生成的潛在客戶**。我到底該如何去做」 – gotva

回答

2

因爲此刻你正在測試是鉛對象接收郵件,您可以存根#lead返回您設置的期望模仿對象:

it "#activate_lead" do 
    lead = double('lead') 
    lg = LeadGeneration.new(contact.id) 
    # make #lead return our test double whenever it's called 
    allow(lg).to receive(:lead) { lead } 
    # our test double should receive the message 
    expect(lead).to receive(:active!) 
    lg.activate_lead 
end 

這意味着你可以移動#lead方法轉換爲私有/受保護的空間,因爲您不必直接調用它。

+0

因此,這是您的標準做法想讓「鉛」這樣的對象是私人的? Thx –

+1

我不會說這個解決方案是一個「標準實踐」,因爲我發佈的解決方案特定於您的測試用例。標準做法是僅製作需要製作的公共方法,然後將其餘部分保留爲私有方法,然後僅測試公共接口(不要直接調用私有方法)。在這種情況下,這是通過「#lead」來實現的。隔離單元測試也是一種很好的做法,這個解決方案通過消除對Lead類的依賴來實現。 –