Search code examples
rubyminiteststderr

Minitest `assert_output` incorrect check for stderr


I need to write some tests for check output to STDERR by minitest
It works fine, if I want to check output to STDOUT, but if try check STDERR - asser_output simply not catch any string in it

So my code looks like this:

require 'minitest/autorun'

class OutputTest < MiniTest::Test
  def test_output_stdout
    assert_output(/Test/, '') {puts 'Test'}
  end

  def test_output_stderr
    assert_output('', /Test/) {STDERR.puts 'Test'}
  end
end

And it gives me error:

 1) Failure:
OutputTest#test_output_stderr [test/assert_test.rb:9]:
In stderr.
Expected /Test/ to match "".

2 runs, 4 assertions, 1 failures, 0 errors, 0 skips

From assert_output documentation second argument of this method is pattern to check of STDERR, but it's not working. What I did wrong?


Solution

  • It works if you use $stderr instead of STDERR:

    assert_output('', /Test/) { $stderr.puts 'Test' }
    

    Internally, assert_output uses the capture_io helper. This swaps $stdout and $stderr with two StringIO, yields the block, and swaps the $stdout and $stderr back. This is possible because $stdout and $stderr are variables.

    STDOUT and STDERR are constants defined on the Object class. Thus they can not be swapped like $stdout and $stderr. When doing STDERR.puts, the output is not captured by minitest helpers and the assertion fails.