結論
rspecの output と to_stderr の組み合わせでは、 $stderr はテストできるが、 STDERR はテストできない。
to_stderr の代わりに、 to_stderr_from_any_process を使えば STDERR もテストできる。ただし、 to_stderr に比べてとっても遅いらしい。
経緯
rspecにて、標準エラーに出力しているコードのテストを書こうとしたところ、to_stderr では STDERR.puts の出力が拾えなかった。
調査
いろいろ試したところ、 $stderr.puts や warn の出力は to_stderr で拾うことができた。
調査結果
こちらによれば、 to_stdout や to_stderr は $stdout や $stderr を一時的に置き換える働きをするので、 STDOUT や STDERR に対しては利用できない、とのこと。
to_stdout_from_any_process や to_stderr_from_any_process であれば、 STDOUT や STDERR に対しても利用できる模様。ただし、 to_stdout や to_stderr に比べてとても遅いらしい。
サンプルコード
# coding: utf-8
describe '標準エラーへの出力' do
context '$stderr(to_stderr)'do
it do
expect { $stderr.print 'error via $stderr' }.to output('error via $stderr').to_stderr
end
end
context 'STDERR(to_stderr)' do
it do
expect { STDERR.print 'error via STDERR' }.to output('error via STDERR').to_stderr
end
end
context '$stderr(to_stderr_from_any_process)'do
it do
expect { $stderr.print 'error via $stderr' }.to output('error via $stderr').to_stderr_from_any_process
end
end
context 'STDERR(to_stderr_from_any_process)' do
it do
expect { STDERR.print 'error via STDERR' }.to output('error via STDERR').to_stderr_from_any_process
end
end
end
サンプルコードの実行結果
% bundle exec rspec
.error via STDERRF..
Failures:
1) 標準エラーへの出力 STDERR(to_stderr) should output "error via STDERR" to stderr
Failure/Error: expect { STDERR.print 'error via STDERR' }.to output('error via STDERR').to_stderr
expected block to output "error via STDERR" to stderr, but output nothing
# ./spec/stderr_spec.rb:10:in `block (3 levels) in <top (required)>'
Finished in 0.03459 seconds (files took 0.11677 seconds to load)
4 examples, 1 failure
Failed examples:
rspec ./spec/stderr_spec.rb:9 # 標準エラーへの出力 STDERR(to_stderr) should output "error via STDERR" to stderr
サンプルコードの実行結果より、 STDERR と to_stderr の組み合わせのとき、標準エラーが拾えていないことがわかる。