我正在测试在控制台上放置一些消息的类(带有放置、p 警告等)。我只是想知道在 RSpec 测试期间是否有任何抑制此输出的能力?
8 回答
puts
我通过重定向$stout
到文本文件来抑制我的类中的输出。这样,如果我出于任何原因需要查看输出,它就在那里,但它不会混淆我的测试结果。
#spec_helper.rb
RSpec.configure do |config|
config.before(:all, &:silence_output)
config.after(:all, &:enable_output)
end
public
# Redirects stderr and stout to /dev/null.txt
def silence_output
# Store the original stderr and stdout in order to restore them later
@original_stderr = $stderr
@original_stdout = $stdout
# Redirect stderr and stdout
$stderr = File.new(File.join(File.dirname(__FILE__), 'dev', 'null.txt'), 'w')
$stdout = File.new(File.join(File.dirname(__FILE__), 'dev', 'null.txt'), 'w')
end
# Replace stderr and stdout so anything else is output correctly
def enable_output
$stderr = @original_stderr
$stdout = @original_stdout
@original_stderr = nil
@original_stdout = nil
end
编辑:
针对@MyronMarston 的评论,将方法直接插入块中before
并after
作为块可能会更聪明。
#spec_helper.rb
RSpec.configure do |config|
original_stderr = $stderr
original_stdout = $stdout
config.before(:all) do
# Redirect stderr and stdout
$stderr = File.new(File.join(File.dirname(__FILE__), 'dev', 'null.txt'), 'w')
$stdout = File.new(File.join(File.dirname(__FILE__), 'dev', 'null.txt'), 'w')
end
config.after(:all) do
$stderr = original_stderr
$stdout = original_stdout
end
end
它看起来更干净一些,并且使方法远离main
. 另外,请注意,如果您使用的是 Ruby 2.0,则可以__dir__
使用File.dirname(__FILE__)
.
编辑2
还应该提到的是,您可以/dev/null
使用File::NULL
Ruby v 1.9.3 中引入的方式转发到真正的操作系统。(jruby 1.7)
然后代码片段将如下所示:
#spec_helper.rb
RSpec.configure do |config|
original_stderr = $stderr
original_stdout = $stdout
config.before(:all) do
# Redirect stderr and stdout
$stderr = File.open(File::NULL, "w")
$stdout = File.open(File::NULL, "w")
end
config.after(:all) do
$stderr = original_stderr
$stdout = original_stdout
end
end
尝试在前块中生成输出的存根方法,例如
before do
IO.any_instance.stub(:puts) # globally
YourClass.any_instance.stub(:puts) # or for just one class
end
这是明确的,所以你不会错过任何你不想错过的东西。如果您不关心任何输出并且上述方法不起作用,您始终可以存根 IO 对象本身:
before do
$stdout.stub(:write) # and/or $stderr if needed
end
Rspec3.0 版本将是 => 在 spec_helper.rb
RSpec.configure do |c|
c.before { allow($stdout).to receive(:puts) }
end
它将充当before(:each)
但是 :each 是默认的,所以不需要显式地写
用 rspec-core (~> 3.4.0) 测试
在描述块中你可以做
# spec_helper.rb
def suppress_log_output
allow(STDOUT).to receive(:puts) # this disables puts
logger = double('Logger').as_null_object
allow(Logger).to receive(:new).and_return(logger)
end
# some_class_spec.rb
RSpec.describe SomeClass do
before do
suppress_log_output
end
end
这样,您就可以为特定测试切换日志输出。请注意,这不会抑制 rspec 警告或来自 rspec 的消息。
另一种禁用来自 gem 的警告的方法:
添加config.warnings = false
到 spec_helper
如果您只想抑制某些记录器方法,就像error, info, or warn
您可以做的那样
allow_any_instance_of(Logger).to receive(:warn).and_return(nil)
禁用来自 rspec gem 的警告
allow(RSpec::Support).to receive(:warning_notifier).and_return(nil)
但通常不鼓励这样做,因为它是为了让你知道你在测试中做了一些有味道的事情。
如果要抑制单个测试的输出,有一种更简洁的方法:
it "should do something with printing" do silence_stream(STDOUT) do foo.print.should be_true end end
如果您的测试打印错误,您可能需要更改STDOUT
为。STDERR
在一次性情况下更新了 Rails 5 的答案:
before do
RSpec::Mocks.with_temporary_scope do
allow(STDOUT).to receive(:puts)
end
end
如果你经常这样做,你可以把它变成 spec_helper 中的一个方法。
在尝试了所有这些示例之后,我最终使用了这种不会使 binding.pry 静音或静音的变体
# frozen_string_literal: true
RSpec.configure do |config|
config.before(:each) do
allow($stdout).to receive(:puts)
allow($stdout).to receive(:write)
end
end
注入默认为 STDOUT 的 IO 对象会很有用。如果您愿意,这也使得在输出上断言更容易。
例如
def my_method(arg, io: STDOUT)
io.puts "hello"
arg.reverse
end
然后在你的测试中:
# Suppress it.
my_method("hi", io: StringIO.new)
# Assert on it.
io = StringIO.new
my_method("hi", io: io)
output = io.tap(&:rewind).read
expect(output).to include("hello")