捕获 Ruby Logger 输出以进行测试

问题描述 投票:0回答:6

我有一个像这样的红宝石课程:

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

测试脚本如下:

#!/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

当我运行此测试时,out 和 err 都是空字符串。我看到打印在 stderr 上的消息(在终端上)。有没有办法让 Logger 和 capture_io 很好地协同工作?

我处于直接的 Ruby 环境中,而不是 Ruby on Rails。

ruby logging minitest
6个回答
8
投票

神奇之处在于使用 capture_subprocess_io

 out, err = capture_subprocess_io do
     do_stuff
 end

5
投票

MiniTest 的

#capture_io
暂时切换
$stdout
$stderr
对象以捕获写入
StringIO
$stdout
的输出。但是
$stderr
有自己对原始标准错误流的引用,它会愉快地写入该流。我认为你可以认为这是一个错误,或者至少是 MiniTest 的
Logger
的限制。

在您的情况下,您将使用参数

#capture_io

在块内创建

Logger
#capture_io
STDERR
仍然指向原始的标准错误流,这就是它不能按预期工作的原因。

STDERR

更改为

STDERR
(此时
确实指向 
$stderr 对象)可以解决此问题,但前提是 Logger 实际上是在 StringIO
 块中创建的,因为在该块之外指向原始标准错误流。
#capture_io

capture_subprocess_io 的文档

2
投票
基本上 Leonard 的示例充实了,并用工作代码进行了评论并指向文档。

将 $stdout 和 $stderr 捕获到字符串中,使用 Tempfile 确保子进程 IO 也被捕获。


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

注意:此方法比 #capture_io 慢大约 10 倍,因此仅在需要测试子进程的输出时才使用它。

参见文档

这是一个老问题,但我们这样做的一种方法是用期望来模拟记录器。类似的东西

0
投票

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

这使我们能够断言被测代码,而无需更改记录器开箱即用的工作方式。

作为

logger.expects(:info).with("Here is an info message")

的示例,我们有一个记录器实现,允许我们传入哈希值并将其输出为 json。当我们测试该实现时,我们使用

capture_io

。这是可能的,因为我们在主题行中使用 
capture_io
 初始化了记录器实现。
$stdout

在测试中

subject { CustomLogging.new(ActiveSupport::Logger.new($stdout)) }

很晚了,但这是对早期答案的回应:

0
投票

https://stackoverflow.com/a/27717477/19637807

在利用 StringIO 的基础上,我们可以使用 minitest 和 mocha 来做类似的事情:

it 'processes a string message' do msg = "stuff" out, err = capture_io do subject.info(msg) end out.must_equal "#{msg}\n" end

这确保了为测试而调用的函数中
    log_output_capture = StringIO.new
    logger = Logger.new(log_output_capture)
    Logger.stubs(:new).returns(logger)
的任何实例都将替换为 StringIO 实例以进行输出。因此,您根本不需要修改底层函数的记录器实现!

我使用 Jikku 的答案通过评估其预期日志输出成功地对 ruby lambda 函数进行了单元测试:

Logger.new

您需要在初始化 

-1
投票
时提供不同的

StringIO

 对象来捕获输出,而不是通常的:
Logger.new
,它实际上指向控制台。
我把上面两个文件稍微修改了一下,做成了一个文件,方便大家复制测试:

STDERR

说明:

方法

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
    在不带参数的情况下使用时将在所有其他代码中正常运行。
  1. 当提供 
    do_something
  2. 方法时,它使用该方法而不是典型的
  3. StringIO
     ,从而能够将输出捕获到文件中或在本例中用于测试。
        
© www.soinside.com 2019 - 2024. All rights reserved.