Suppress console output during RSpec tests

I suppress puts output in my classes by redirecting $stout to a text file. That way, if I need to see the output for any reason, it is there but it doesn't muddy up my test results.

#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

EDIT:

In response to the comment by @MyronMarston, it probably would be smarter to just insert the methods directly into before and after as blocks.

#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

It looks a little cleaner and keeps methods off of main. Also, note that if you are using Ruby 2.0, you can use __dir__ instead of File.dirname(__FILE__).

EDIT2

Also it should be mentioned, that you can forward to true os /dev/null by using File::NULL as it was introduced in Ruby v 1.9.3. (jruby 1.7)

Then the code snippet will look as following:

#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

Try stubbing methods that make the output in a before block, e.g.

before do
  IO.any_instance.stub(:puts) # globally
  YourClass.any_instance.stub(:puts) # or for just one class
end

This is explicit, so you won't miss anything you don't want to miss. If you don't care about any output and the method above doesn't work you can always stub the IO object itself:

before do
  $stdout.stub(:write) # and/or $stderr if needed
end

Tags:

Ruby

Rspec