怎么用ruby控制输出到控制台?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (7)

我正在编写如下的单元测试:

def executing_a_signal
  a_method(a_signal.new, a_model, a_helper);
  assert_equal(new_state, a_model.state)
end

测试工作正常,但在断言执行逻辑之前运行的方法将各种消息输出到控制台,主要是通过puts

有没有一种快速的,也许是内置的方法来抑制输出到控制台?我只对该方法在模型对象上的最终效果感兴趣,为了基本保持控制台清洁,我希望找到一种方法来简单地防止所有输出到控制台而不重写或注释掉puts声明只是为了我的测试。

提问于
用户回答回答于

我在测试中使用以下代码片段来捕获和测试STDOUT

def capture_stdout(&block)
  original_stdout = $stdout
  $stdout = fake = StringIO.new
  begin
    yield
  ensure
    $stdout = original_stdout
  end
  fake.string
end

通过这种方法,上述将变成:

def executing_a_signal
  capture_stdout { a_method(a_signal.new, a_model, a_helper) }
  assert_equal(new_state, a_model.state)
end
用户回答回答于

有两种解决方案:重定向puts写入,或覆盖puts方法本身为nil。(实现应该很明显:)module Kernel; def puts(*args) end end

因此,另一种解决方案是让Model对象将日志记录到Logger对象的责任,并使用依赖注入将适当的Logger对象注入到Model对象中。这样,可以简单地为测试注入记录器。这是一个例子:

#!/usr/bin/env ruby

class SomeModel
  def initialize(logger=Kernel) @logger = logger end
  def some_method_that_logs; @logger.puts 'bla' end
end

require 'test/unit'
require 'stringio'
class TestQuietLogging < Test::Unit::TestCase
  def setup; @old_stdout, $> = $>, (@fake_logdest = StringIO.new) end
  def teardown; $> = @old_stdout end

  def test_that_default_logging_is_still_noisy
    SomeModel.new.some_method_that_logs

    assert_equal "bla\n", @fake_logdest.string
  end

  def test_that_logging_can_be_made_quiet
    fake_logger = Object.new
    def fake_logger.puts *args; end

    SomeModel.new(fake_logger).some_method_that_logs

    assert_equal '', @fake_logdest.string
  end
end

最起码,Model对象应采取IO它记录对象来作为参数,这样就可以简单地注入StringIO.new到它的测试:

#!/usr/bin/env ruby

class SomeModel
  def initialize(logdest=$>) @logdest = logdest end
  def some_method_that_logs; @logdest.puts 'bla' end
end

require 'test/unit'
require 'stringio'
class TestQuietLogging < Test::Unit::TestCase
  def setup; @old_stdout, $> = $>, (@fake_logdest = StringIO.new) end
  def teardown; $> = @old_stdout end

  def test_that_default_logging_is_still_noisy
    SomeModel.new.some_method_that_logs

    assert_equal "bla\n", @fake_logdest.string
  end

  def test_that_logging_can_be_made_quiet
    fake_logdest = (@fake_logdest = StringIO.new)

    SomeModel.new(fake_logdest).some_method_that_logs

    assert_equal '', @fake_logdest.string
    assert_equal "bla\n", fake_logdest.string
  end
end

class SomeModel
  def initialize(logdest=$>) @logdest = logdest end
  def some_method_that_logs; puts 'bla' end
  private
  def puts(*args) @logdest.puts *args end
end

扫码关注云+社区