在RSpec测试期间抑制控制台输出

dem*_*mas 42 ruby rspec

我正在测试在控制台上放置一些消息的类(带有puts,p警告等).我只是想知道在RSpec测试期间是否有能力抑制此输出?

Cha*_*ell 40

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
Run Code Online (Sandbox Code Playgroud)

编辑:

在回应@MyronMarston的评论时,将方法直接插入beforeafter作为块可能会更聪明.

#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
Run Code Online (Sandbox Code Playgroud)

它看起来更清洁,并保持方法main.另请注意,如果您使用的是Ruby 2.0,则可以使用__dir__而不是File.dirname(__FILE__).

EDIT2

还应该提到的是,你可以/dev/null使用File::NULLRuby 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
Run Code Online (Sandbox Code Playgroud)

  • 这是一个非常好的解决方案,但请记住,它将`silence_output`和`enable_output`添加到系统中的每个对象.我认为在小型一次性脚本中这样做很好,但是我避免在`main`上定义方法. (3认同)

Mic*_*ski 28

尝试使用在前块中输出的存根方法,例如

before do
  IO.any_instance.stub(:puts) # globally
  YourClass.any_instance.stub(:puts) # or for just one class
end
Run Code Online (Sandbox Code Playgroud)

这是明确的,所以你不会错过任何你不想错过的东西.如果您不关心任何输出并且上述方法不起作用,您可以始终存根IO对象本身:

before do
  $stdout.stub(:write) # and/or $stderr if needed
end
Run Code Online (Sandbox Code Playgroud)


小智 20

在spec_helper.rb中,Rspec3.0版本将是=>

RSpec.configure do |c|
  c.before { allow($stdout).to receive(:puts) }
end
Run Code Online (Sandbox Code Playgroud)

它会充当 before(:each)

但是:每个都是默认的,所以不需要明确地写它

  • stub:`write`而不是`:puts`为我工作. (3认同)

lfe*_*445 14

用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
Run Code Online (Sandbox Code Playgroud)

这样,您就可以切换特定测试的日志输出.请注意,这不会抑制rspec警告或来自rspec的消息.

另一种禁用来自宝石的警告的方法:

添加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)

但这通常是气馁的,因为它意味着让你知道你在测试中做了些什么.


sho*_*one 10

如果要抑制单个测试的输出,则有一种更简洁的方法:

it "should do something with printing" do
  silence_stream(STDOUT) do
    foo.print.should be_true
  end
end
Run Code Online (Sandbox Code Playgroud)

如果测试打印出错误,您可能需要更改STDOUTSTDERR.

  • [silence_stream现已弃用](http://www.rubydoc.info/gems/activesupport/4.2.0/Kernel:silence_stream) (6认同)
  • 我想要注意[silence_stream](http://apidock.com/rails/Kernel/silence_stream)是[activesupport](http://apidock.com/rails/ActiveSupport)的一部分. (3认同)

con*_*t47 7

在一次性情况下更新了Rails 5的答案:

before do
  RSpec::Mocks.with_temporary_scope do
    allow(STDOUT).to receive(:puts)
  end
end
Run Code Online (Sandbox Code Playgroud)

如果你要做很多事情,你可以把它变成spec_helper中的方法.


Chr*_*ugh 5

在尝试了所有这些示例之后,我最终使用了这个不会使 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
Run Code Online (Sandbox Code Playgroud)

  • 这是该线程上唯一对我有用的解决方案。对我来说,只有“write”上的存根是必要的。 (4认同)