2015-02-06 30 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