Capturing Ruby Logger for testing

I have a ruby ​​class:

require 'logger' class T def do_something log = Logger.new(STDERR) log.info("Here is an info message") end end 

And the test line of the script:

 #!/usr/bin/env ruby gem "minitest" require 'minitest/autorun' require_relative 't' class TestMailProcessorClasses < Minitest::Test def test_it me = T.new out, err = capture_io do me.do_something end puts "Out is '#{out}'" puts "err is '#{err}'" end end 

When I run this test, both out and err are empty lines. I see a message printed on stderr (on the terminal). Is there a way to make Logger and capture_io fit well together?

I am in a direct Ruby environment, not Ruby on Rails.

+5
source share
4 answers

Magic - use capture_subprocess_io

  out, err = capture_subprocess_io do do_stuff end 
+4
source

MiniTest #capture_io temporarily switches $stdout and $stderr for StringIO objects to write the output written to $stdout or $stderr . But Logger has its own link to the original standard error stream, which he will gladly write. I think you can consider this a mistake, or at least a limitation of MiniTest #capture_io .

In your case, you create a Logger inside the block before #capture_io with the argument STDERR . STDERR still points to the original standard error stream, so it does not work properly.

Changing STDERR to $stderr (which at these points points to a StringIO object) works around this problem, but only if Logger is actually created in the #capture_io block, because outside it block it indicates the original standard error stream.

 class T def do_something log = Logger.new($stderr) log.info("Here is an info message") end end 
+5
source

Documentation capture_subprocess_io

Basically, Leonard's example worked with working code and pointed to documents (not allowed to edit!)

 out, err = capture_subprocess_io do system "echo Some info" system "echo You did a bad thing 1>&2" end assert_match %r%info%, out assert_match %r%bad%, err 

See documentation

+1
source

You need to provide another StringIO object when initializing Logger.new in order to capture the output, not the usual one: STDERR , which actually points to the console.

I modified these two files a bit and made one file so that you can copy and test easily and easily:

 require 'logger' require 'minitest' class T def do_something(io = nil) io ||= STDERR log = Logger.new io log.info("Here is an info message") end end class TestT < Minitest::Test def test_something t = T.new string_io = StringIO.new t.do_something string_io puts "Out: #{string_io.string}" end end Minitest.autorun 

Explanation:

  • The do_something method will function normally in all other code when used without an argument.
  • When the StringIO method is StringIO , it uses this instead of the typical STDERR , which allows you to write the output as a file, or in this case for testing.
-1
source

Source: https://habr.com/ru/post/1210158/


All Articles