2015-02-06 66 views
2

我一直在嘗試使用Minitest來測試我的代碼(full repo),但是在從.txt下載SHA1哈希的一種方法遇到問題文件在網站上並返回值。Minitest:如何在URL上殘留/模擬Kernel.open的文件結果

方法:

def download_remote_sha1 
    @log.info('Downloading Elasticsearch SHA1.') 

    @remote_sha1 = '' 
    Kernel.open(@verify_url) do |file| 
    @remote_sha1 = file.read 
    end 

    @remote_sha1 = @remote_sha1.split(/\s\s/)[0] 

    @remote_sha1 
end 

你可以看到,我記錄的內容發生在命令行,創建一個對象來保存我的SHA1值,打開網址(如https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.4.2.deb.sha1.txt

我再拆該字符串,以便我只有SHA1值。

問題是,在測試過程中,我想對使用OpenURI打開URL的Kernel.open進行存根。我想確保我沒有真正下載任何文件,但是我只是通過阻止我自己的模擬IO對象來測試它是否正確地分割了一些東西。

我試過它像下面的塊,但是當@remote_sha1 = file.read發生時,文件項目是零。

@mock_file = Minitest::Mock.new 
@mock_file.expect(:read, 'd377e39343e5cc277104beee349e1578dc50f7f8 elasticsearch-1.4.2.deb') 

Kernel.stub :open, @mock_file do 
    @downloader = ElasticsearchUpdate::Downloader.new(hash, true) 
    @downloader.download_remote_sha1.must_equal 'd377e39343e5cc277104beee349e1578dc50f7f8' 
end 
+1

嗨,你能請ACC埃普馬特的答案,而不是我的?在我想清楚發生了什麼之前,他發佈了正確的答案。謝謝。 – 7stud 2015-02-07 06:05:28

回答

2

的第二個參數stub是你想要的返回值成爲測試的持續時間是什麼,但方式Kernel.open在這裏使用要求它屈服於塊價值而不是改變。

您可以通過提供第三個參數來實現此目的。嘗試改變調用Kernel.stub

Kernel.stub :open, true, @mock_file do 
    #... 

注意額外的參數true,使@mock_file現在是第三個參數,將產生的塊。在這種情況下,第二個參數的實際值並不重要,您可能也想在此使用@mock_file以更接近地對應於open的行爲方式。

3

我也在研究這個問題,但是matt首先想到了它。要添加到什麼貼matt

當你寫:

Kernel.stub(:open, @mock_file) do 
    #block code 
end 

...這意味着當Kernel.open()被稱爲 - 在任何代碼,隨時隨地存根()塊ends-前 - 返回值爲Kernel.open()將爲@mock_file。但是,你永遠不會在你的代碼中使用Kernel.open()的返回值:

Kernel.open(@verify_url) do |f| 
    @remote_sha1 = f.read 
end 

如果你想使用Kernel.open()的返回值,你會寫:

return_val = Kernel.open(@verify_url) do |f| 
    @remote_sha1 = f.read 
end 

#do something with return_val 

因此,Kernel.open()的返回值在你的代碼中是不相關的 - 這意味着stub()的第二個參數是不相關的。

source code for stub()的仔細檢查表明,存根()採用第三個參數 - 這將被傳遞到的存根方法調用之後指定的參數。你,其實,有你的存根Kernel.open()方法調用之後指定塊:

stubbed method call -+  +- start of block 
      |  |  | 
      V  V  V 
    Kernel.open(@verify_url) do |f| 
     @remote_sha1 = f.read 
    end 
    ^
    | 
    end of block 

因此,爲了@mockfile傳遞給你需要將其指定爲第三個參數爲內核塊。存根():

Kernel.stub(:open, 'irrelevant', @mock_file) do 

end 

這裏是未來的搜索一個完整的例子:

require 'minitest/autorun' 

class Dog 
    def initialize 
    @verify_url = 'http://www.google.com' 
    end 

    def download_remote_sha1 
    @remote_sha1 = '' 

    Kernel.open(@verify_url) do |f| 
     @remote_sha1 = f.read 
    end 

    #puts @remote_sha1[0..300] 
    @remote_sha1 = @remote_sha1.split(" ")[0] #Using a single space for the split() pattern will split on contiguous whitespace. 

    end 
end 

#Dog.new.download_remote_sha1 

describe 'downloaded file' do 
    it 'should be an sha1 code' do 
    @mock_file = Minitest::Mock.new 
    @mock_file.expect(:read, 'd377e39343e5cc277104beee349e1578dc50f7f8 elasticsearch-1.4.2.deb') 

    Kernel.stub(:open, 'irrelevant', @mock_file) do 
     @downloader = Dog.new 
     @downloader.download_remote_sha1.must_equal 'd377e39343e5cc277104beee349e1578dc50f7f8' 
    end 
    end 
end 

XXX