2012-11-01 48 views
4

如何用rspec測試這樣的代碼?如何測試ActiveRecord創建塊內的行爲?

Foo.create! do |foo| 
    foo.description = "thing" 
end 

我不想測試被創建的對象 - 我想測試是否正確的方法被正確的對象調用。等效於測試這一點:

Foo.create!(description: "thing") 

與此:

Foo.should_receive(:create!).with(description: "thing") 
+0

有些東西不需要測試,除非描述是自定義方法,或者這是學術興趣? – antiqe

+0

我需要確保我的客戶端代碼將正確的對象分配給正確的屬性 –

回答

1

這是你以後在做什麼?

it "sets the description" do 
    f = double 
    Foo.should_receive(:create!).and_yield(f) 
    f.should_receive(:description=).with("thing") 

    Something.method_to_test 
end 
0
Foo.count.should == 1 
Foo.first.description.should == 'thing' 
+0

但我不想測試基礎的持久性行爲 - 我想測試代碼是否將正確的對象設置到正確的位置。我現在給我的問題添加了更多細節。 –

+0

「我想測試正確的對象是否調用了正確的方法。」 你可以通過指定結果狀態來做到這一點,就像@ antiqe的例子。您認爲通過指定使用'description ='還是'write_attribute(:description,「value」)'或任何其他可供選擇的替代方法,您會獲得哪些好處? –

+0

@DavidChelimsky的目標是不測試AR創建的持久性質量。我知道每個我正在測試的方法都能正常工作,所以爲了測試使用它們的函數,我可以測試它們是否被調用。我知道這並不是那麼漂亮,而新的熱度似乎永遠不會做控制器規格的原因 - 只有響應和/或整合。但無論如何回到你的觀點 - 是的,這是真的,兩種方法都會有相同的行爲,所以我應該測試他們的結果。所以我想FG build_stubbed並測試結果值可能是一個很好的整體解決方案。思考? –

0

下面是一個組合方法,它將@ antiqe和@Fitzsimmons的答案中的最佳值合併在一起。儘管如此,它明顯更加冗長。

這個想法是模仿Foo.create,其行爲更像AR :: Base.create。弗里斯特,我們定義了一個輔助類:

class Creator 
    def initialize(stub) 
    @stub = stub 
    end 

    def create(attributes={}, &blk) 
    attributes.each do |attr, value| 
     @stub.public_send("#{attr}=", value) 
    end 

    blk.call @stub if blk 

    @stub 
    end 
end 

,然後我們可以在我們的規格使用它:

it "sets the description" do 
    f = stub_model(Foo) 
    stub_const("Foo", Creator.new(f)) 

    Something.method_to_test 

    f.description.should == "thing" 
end 

你也可以使用FactoryGirl.build_stubbed代替stub_model。但是,您不能使用mock_modelmockdouble,因爲您再次遇到同樣的問題。

現在你的規範將通過以下任何代碼片段:

Foo.create(description: "thing") 

Foo.create do |foo| 
    foo.descrption = "thing" 
end 

foo = Foo.create 
foo.descrption = "thing" 

的寶貴意見!