我有一个像这样的红宝石课程:
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。
神奇之处在于使用 capture_subprocess_io
out, err = capture_subprocess_io do
do_stuff
end
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 的文档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")
capture_io
。这是可能的,因为我们在主题行中使用
capture_io
初始化了记录器实现。
$stdout
在测试中
subject { CustomLogging.new(ActiveSupport::Logger.new($stdout)) }
很晚了,但这是对早期答案的回应:
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
您需要在初始化
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
当提供
do_something
StringIO
,从而能够将输出捕获到文件中或在本例中用于测试。