2013-02-19 53 views
10

我有一個函數,它接受一個塊,打開一個文件,收益率和回報:如何測試一個函數,它接受一個塊使用RSpec

def start &block 
    .....do some stuff 
    File.open("filename", "w") do |f| 
     f.write("something") 
     ....do some more stuff 
     yield 
    end 
end 

我試圖寫一個測試使用RSpec的它。如何將File.open存根以便它將一個對象f(由我提供)傳遞給該塊而不是試圖打開實際文件?喜歡的東西:

it "should test something" do 
    myobject = double("File", {'write' => true}) 
    File.should_receive(:open).with(&blk) do |myobject| 
     f.should_receive(:write) 
     blk.should_receive(:yield) (or somethig like that) 
    end 
end 
+1

很難對此進行測試,因爲您想要測試的是該方法的內部。你的文件如何與方法外的任何東西進行交互?在你的例子中,你根本不會在方法外部使用這個文件,也不會產生它。如果這個函數之外的東西需要該文件,那麼也許你應該考慮將文件對象傳遞給方法(依賴注入)。然後你可以模擬文件沒問題。如果你確實需要測試一下這個文件,也許你應該考慮把它分解成一個單獨的方法? – Raj 2013-02-27 01:03:34

+0

謝謝...做了這樣的事情,分解成多個方法,像File.stub(打開).and_yield(my_double)等殘存幾個功能。 – constantine1 2013-03-05 09:07:48

回答

3

我想你要尋找的是yield matchers,即:

it "should test something" do 
    # just an example 
    expect { |b| my_object.start(&b) }.to yield_with_no_args 
end 
+0

如何存根File.open在函數內部提供一個模擬對象開始)正在測試? – constantine1 2013-02-19 11:34:18

+0

讓我重申 - 我如何存根File.open提供一個模擬對象到它的塊,以便我可以測試像f.should_receive(:write).with(「應該寫入文件」) – constantine1 2013-02-19 12:04:51

+0

我錯過了您的評論,僅今天點擊「回覆」。基本上File.open發送block * self *(嘗試在block內部運行'puts f.inspect'),所以嘲笑'File.should_receive(:write)'應該可以工作。對不起,對於遲到的回覆,但希望這會對某人有用:) – Amir 2013-06-19 19:16:07

1

你的其他選擇是存根:以文件的一個新對象開放,因爲這樣:

file = File.new 
allow(File).to receive(:open) { file } 
file.each { |section| expect(section).to receive(:write) } 
# run your method 
+0

請注意這一點。根據我的經驗,我發現如果你在基本的系統類上使用RSpec存根/ mock,比如'File',它往往會導致很多問題。例如,如果您在測試中使用VCR gem,如果允許(File)。接收幾乎任何東西,它將以驚人的方式突破。 – Jazz 2015-05-15 17:19:17

相關問題