我一直在尝试使用Minitest来测试我的代码(full repo),但是在使用一种从网站上的.txt文件下载SHA1哈希并返回值的方法时遇到问题。
方法:
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
出现时,文件项是nil。
@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
答案 0 :(得分:4)
我也在研究这个问题,但是matt
首先想出来了。添加到matt
发布的内容:
当你写:
Kernel.stub(:open, @mock_file) do
#block code
end
...这意味着在调用Kernel.open()
时 - 在任何代码中,任何地方在stub()块结束之前 - 返回值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()会发现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()的第三个参数:
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
答案 1 :(得分:2)
stub
的第二个参数是您希望返回值在测试期间的内容,但此处使用Kernel.open
的方式需要值屈服于要改变的块。
您可以通过提供第三个参数来实现此目的。尝试将通话更改为Kernel.stub
至
Kernel.stub :open, true, @mock_file do
#...
注意额外的参数true
,这样@mock_file
现在是第三个参数,并将被提供给块。在这种情况下,第二个参数的实际值并不重要,您可能也想在@mock_file
使用open
来更接近{{1}}的行为。