在一个方法中,我有多个调用另一个带有不同参数的方法。我只想测试一个特定的调用,看看该调用的参数是否符合某些条件。有没有更好的方法来阻止其他所有的电话?
例如,我有
def some_method
foo(1)
foo('a')
foo(bar) if ... # some complex logic
foo(:x)
...
end
我只想测试foo
是否实际使用参数bar
调用。
subject.should_receive(:foo).with(correct_value_of_bar)
但是如何处理同一foo
内的some_method
的其他来电?
答案 0 :(得分:1)
好的,基于您的最新评论,您希望观察到您正在记录一些输出。这是一个通过用StringIO实例替换STDOUT来观察此行为的示例:
# foo.rb
require 'rubygems'
require 'rspec'
require 'rspec/autorun'
require 'stringio'
class Foo
def something
puts 1
puts 'a'
puts 'bar' if true # some complex logic
puts :x
end
end
describe Foo do
describe '#something' do
context "and something complex happens" do
let(:io){ StringIO.new }
it "logs to STDOUT" do
$stdout = io
Foo.new.something
expect(io.tap(&:rewind).read).to include("bar\n")
end
end
end
end
这样可行,但这样做的副作用远远超出了您的具体示例,因为我们正在更改全局$stdout
。这可以通过使用穷人的依赖注入和构造函数默认值来改进:
class Foo
def initialize(io=STDOUT)
@io = io
end
def something
puts 1
puts 'a'
puts 'bar' if true # some complex logic
puts :x
end
protected
def puts(*args)
@io.puts *args
end
end
describe Foo do
describe '#something' do
context "and something complex happens" do
let(:io){ StringIO.new }
it "logs to STDOUT" do
Foo.new(io).something
expect(io.tap(&:rewind).read).to include("bar\n")
end
end
end
end
在上面的例子中,我们给自己传递了我们将要放入的IO对象的能力。这让我们可以观察行为而不会产生超出测试范围的副作用,并且让我们正在测试的对象保持对自己的真实性(即:我们不像以前那样修改对象本身但是现在删除了关于使用建议的as_null_object
的评论。
您还可以在构造函数上使用选项哈希,并将惰性赋值推送到initialize
本身:
def initialize(arg1, arg2, options={})
@io = options[:io] || STDOUT
end
您还可以升级简单puts
以使用实际的Logger对象。然后你可以在一个地方测试你的记录器使用STDOUT,STDERR或任何地方,你可以测试你记录它记录到info
,debug
等的记录的所有对象适当。
你也可以在更多的方向上采取这个方法,但是如果不知道你正在做什么,这个潜在的答案可能已经足够长了。
希望通过观察行为而不是依赖于内部实现细节(例如您使用puts
本身而不是print "bar\n"
这一事实,这可以为您提供一些关于如何处理此问题的建议。或者另一种将文本输出到IO对象的方法。