2012-11-28 29 views
7

假設我有Car和Mechanic類。汽車有「跑」的方法。機械師出於某種原因需要汽車。然後我寫RSpec規格。在技​​工中,我定義了一個這樣的假類:用於僞造類常量的RSpec規範的最佳做法或解決方法

class Car; end 

和更高版本存根機械使用它的方法。如果我單獨運行測試,所有工作正常。但是當我將兩個測試一起運行時(rspec spec/directory /),我的機械規格使用真正的Car類。

所以。我想這是因爲紅寶石類是「開放」的,我已經爲Car規格加載過一次類。但有沒有更好的方法來做到這一點?什麼是這種情況的最佳實踐?這是否意味着我的代碼需要一些改進,因爲它可能緊密耦合?

我在github上做了一個快速演示:https://github.com/depy/RspecTest

回答

2

這個假類不會工作,因爲Ruby類是開放的。

您可以使用的一種方法是使用let以您想要的方式初始化對象,並在需要時使用before塊的關係。在前面的街區內,存根也是受歡迎的。 = p

希望這可以幫助你!

+0

但有時當我需要一些類包含其他的類。在需要之前,我必須僞造「其他」。那個怎麼樣? –

+0

這就是我告訴過你在前一個街區做的行爲。就像你可以有2個讓,每個類有1個,並且在前面的塊上,你可以根據第一個來調用一個存根來返回另一個對象。 –

2

我想你需要的是兩層測試:

  • 單元規格:單獨測試每個類
  • 集成規格:測試整個

給予代碼如下:

class Car 
end 

class Mechanic 
    def fix(car) 
    # do something here 
    end 
end 

對於單位規格,我會存根相關性,例如:

describe Mechanic do 
    let(:mechanic) { described_class.new } 
    let(:car)  { stub(stubbed_method_on_car: 14) } # Or just OpenStruct.new(stubbed_method_on_car: 14) 

    it 'does some stuff' do 
    mechanic.fix(car).should eq true 
    end 
end 

對於整合規範我這樣做:

describe Mechanic do 
    let(:mechanic) { FactoryGirl.create(:mechanic) } 
    let(:car)  { FactoryGirl.create(:car) } 

    it 'does some stuff' do 
    mechanic.fix(car).should eq true 
    end 
end 
+0

對於單元規格,你能描述兩個'let'方法的塊在做什麼嗎? – knownasilya

+0

嗯。實際的例子是我有NotificationService,它具有由Task實例調用的發佈方法。並在NotificationService.publish內部創建併發布Notification對象。我不想讓任務知道任何有關NotificationClass的知識,它只是知道它可以使用NotificationService進行發佈,而服務可以完成所有其他的任務。但是我該如何單元測試,並且能夠將所有單元測試一起運行,而不是單獨進行。我不希望NotificationService使用真正的Notification類,因爲Notification測試重寫了它。我希望它明確表示...... :) –

+0

@Knownasilya:簡單地說'let'設置一個訪問器到實例變量':mechanic' - >'@ mechanic',它在每個示例之後重置爲原始狀態 –