Ruby 如何恰当地模拟一个返回yield的方法?
在Ruby中,采用块的方法很常见,如下所示:Ruby 如何恰当地模拟一个返回yield的方法?,ruby,unit-testing,rspec,ruby-mocha,Ruby,Unit Testing,Rspec,Ruby Mocha,在Ruby中,采用块的方法很常见,如下所示: class File def open(path, mode) perform_some_setup yield ensure do_some_teardown end end def frobnicate File.open('/path/to/something', 'r') do |f| f.grep(/foo/).first end end 方法的外观也是非常惯用的: class Fil
class File
def open(path, mode)
perform_some_setup
yield
ensure
do_some_teardown
end
end
def frobnicate
File.open('/path/to/something', 'r') do |f|
f.grep(/foo/).first
end
end
方法的外观也是非常惯用的:
class File
def open(path, mode)
perform_some_setup
yield
ensure
do_some_teardown
end
end
def frobnicate
File.open('/path/to/something', 'r') do |f|
f.grep(/foo/).first
end
end
我想为此编写一个不影响文件系统的规范,确保它从文件中提取正确的单词,比如:
describe 'frobnicate' do
it 'returns the first line containing the substring foo' do
File.expects(:open).yields(StringIO.new(<<EOF))
not this line
foo bar baz
not this line either
EOF
expect(frobnicate).to match(/foo bar baz/)
end
end
描述“Frobnite”的用法
它“返回包含子字符串foo”do的第一行
File.expects(:open).yields(StringIO.new(似乎您只需要稍微不同地模拟对File
的调用。我在原样运行您的代码时遇到语法错误,因此我不确定您使用的是哪个版本的RSpec,但如果您使用的是3.x,这将完成以下工作:
Frobnite_spec.rb
gem'rspec',“~>3.4.0”
需要“rspec/自动运行”
RSpec.configure do | config|
config.mock_with:rspec
结束
def泡沫酸盐
打开('/path/to/something',r')do | f|
f、 grep(/foo/)。首先
结束
结束
RSpec.description“frobnite”do
它“返回包含子字符串foo”do的第一行
允许(文件)。接收(:打开)。并调用原始
允许(文件).to receive(:open).and_yield StringIO.new使用minitest可以像我下面发布的那样完成。我添加了整个可运行文件,因此您可以使用ruby-Ilib:test test_File.rb从命令行对其进行测试:
def frobnicate
found_string = nil
File.open('/path/to/something', 'r') do |f|
found_string = f.grep(/foo/).first
end
found_string
end
class FrabnicateTest < Minitest::Test
def test_it_works
mock_file = StringIO.new(%(
not this line
foo bar baz
not hthis line either
))
search_result = nil
File.stub(:open, nil, mock_file) do
search_result = frobnicate
end
assert_match(/foo bar baz/, search_result)
end
end
def泡沫酸盐
找到字符串=零
打开('/path/to/something',r')do | f|
找到\u string=f.grep(/foo/)。第一个
结束
找到你的字符串
结束
类FrabnicateTest<最小测试::测试
def测试功能正常
mock_file=StringIO.new(%)(
不是这条线
福吧巴兹酒店
这条线也不行
))
搜索结果=nil
存根(:open,nil,mock_File)do
搜索结果=Frobnite
结束
断言匹配(/foo-bar-baz/,搜索结果)
结束
结束
啊,对于语法错误,我很抱歉;为了得到一个MWE,我削减了很多原始代码。看起来你的解决方案是通过rspec mock实现的,而我写的是通过Mocha实现的。不幸的是,当我使用你的解决方案时,我得到了一个未定义的方法allow
;我使用的是rspec 3.4.1。你使用的是什么Ruby版本?忽略-我更新了test设置,以避免与Mocha的冲突。刚刚用rubies 1.9.3、2.0.0和2.1.2进行了尝试,我可以肯定问题出在config.mock_上。一旦设置到位,我可以模拟调用以打开该特定文件并完全实现我想要的。感谢您的帮助!我真正想要避免的是编辑frobnite
的定义只是为了让一些测试能够针对它运行。测试服务于代码,而不是相反。测试的困难在于有一种气味告诉我们应该在测试的代码上做得更好。TDD对我来说的一个卖点是测试鼓励我们编写更好的代码。你的代码在我看来会更好f它没有对文件类的依赖项进行硬编码。你可以比我更信任minitest的创建者:在internet上搜索有关硬编码依赖项的信息。这样代码就可以轻松地使用(也可以进行测试)。