2012-07-27 71 views
3

我試圖存根File.open爲了測試我有讀取CSV文件的方法。與Rspec Stubbing File.open

這裏的模型:

class BatchTask 
    def import(filename) 
    CSV.read(filename, :row_sep => "\r", :col_sep => ",") 
    end 
end 

這裏的規範代碼:

let(:data) { "title\tsurname\tfirstname\rtitle2\tsurname2\tfirstname2\r"} 
let(:result) {[["title","surname","firstname"],["title2","surname2","firstname2"]] } 

it "should parse file contents and return a result" do 
    File.stub(:open).with("file_name","rb") { StringIO.new(data) } 
    person.import("file_name").should == result 
end 

然而,當我試圖做到這一點,我得到(堆棧跟蹤):

Errno::ENOENT in 'BatchTask should parse file contents and return a result' 
No such file or directory - file_name 
/Users/me/app/models/batch_task.rb:4:in `import' 
./spec/models/batch_task_spec.rb:10: 

Finished in 0.006032 seconds 

我我一直在抨擊這個人,並且無法弄清楚我做錯了什麼。任何幫助將不勝感激!

+0

stacktrace加上確切的錯誤 – Sly 2012-07-27 18:39:33

回答

8

提供一個堆棧跟蹤會很有幫助,但我會猜測它爲什麼會發生。另外,我相信你在這裏的做法不好,我會詳細說明我相信你應該測試。

簡單地說,我認爲CSV.read不使用File.open。它可以使用Kernel#open或其他各種方式在Ruby中打開文件。不管怎樣,你不應該在測試中存根File.open

有一個叫Growing Object-Oriented Software Guided by Tests偉大的書,有一個需要規則:

存根只在類/接口方法可以控制

有一個很簡單的理由。當你做測試雙打(存根)時,主要原因是界面發現 - 你想弄清楚你的班級界面應該是什麼樣子,雙打爲你提供整潔的反饋。還有一個次要原因 - 在某些情況下(當圖書館不是非常糟糕的時候),外部圖書館的存根往往非常棘手。因此,您可以採取幾種不同的方法,我會列舉:

  1. 您可以在集成中進行測試。您可以在每個測試中創建文件並傳遞路徑名(這很好)。
  2. 你可以打破你解析的方式。而不是傳遞一個文件名CSV.read,找到一種方法,當你通過一個開放的File,然後存根在測試。即讓您的代碼打開文件而不是CSV。這樣你可以輕鬆地存根
  3. 存根CSV.read而不是。這可能有點戲劇性,但實質上,你沒有測試你的代碼,你正在測試CSV庫。它應該已經有了自己的測試,並且無論如何你都不需要測試它。相反,你可以依靠它的工作原理,只是對它的調用存根。

其中,我可能會去第三個。我不喜歡在單元測試中測試依賴關係。但如果你想讓你的測試調用該代碼,我建議找到一種方法來做第二個選項(CSV.new(file)應該做的伎倆,但我沒有時間調查),並最終回落到#1,如果沒有其他的作品。

+0

感謝您的深思熟慮的答案!這肯定給我一個很好的視角去思考如何前進。保存CSV.read方法似乎是最好的方法。再次感謝! – Sly 2012-07-30 17:20:20

+0

不客氣:) – 2012-07-31 07:57:20