在ruby中,如何使用puts和实例变量捕获stdout。我需要使用实例变量来传递rspec测试

时间:2014-04-17 21:45:21

标签: ruby rspec stdout

为了清晰起见,将相关的代码片段从我的项目提取到一个小的独立测试模块......

require "stringio"  

@output = $stdout
$buffer = StringIO.new
$stdout = $buffer

@output.puts "puts method to buffer text" 
$stdout = STDOUT 

$buffer.rewind 
puts "buffer contents: #{$buffer.read}"

运行此代码,返回一个空缓冲区。我必须使用@ output.puts传递一个rspec @output(:puts)should_receive rspec测试。如果我用简单的“puts”替换@ output.puts,则填充缓冲区但rspec测试失败。

我已经搜索了几个小时的在线红宝石资源,并且不能使用任何内容来回答这个问题。任何帮助都感激不尽。

3 个答案:

答案 0 :(得分:0)

试试这个:

require 'stringio'

def read_stdout(&block)
  tmp = $stdout
  $stdout = tmp = StringIO.new
  block.call
  tmp.string
  ensure
   $stdout = tmp # ensures that always evaluated
end

答案 1 :(得分:0)

行。最后的简单错误。

首先,插入

$buffer.write

行意味着我实际上是在写缓冲区,所以它不是空的!

其次,

@output.puts("string")

实际上并没有将字符串内容分配给@output,只是将它用作输出通道所以

$buffer.write(@output) 

只是将十六进制字符而不是我的字符串写入缓冲区。

所以我必须明确地写字符串或将其分配给变量,即

@output="string"
$buffer.write(@output)

将字符串写入缓冲区。

感谢所有回应,这些回应让我以正确的方式 - 向前和向上 - 进行研究/思考。

答案 2 :(得分:-1)

你可以重新设计你的代码,不依赖于put并允许注入它写入的输出流,STDOUT是默认值,因此你的应用代码不必改变。

class Foo
  def something_cool
    puts "this is an artifact I want to test"
  end
end

...变为

class Foo
  def initialize(out=STDOUT)
    @out = out
  end

  def something_cool
    output "this is an artifact I want to test"
  end

  private
  def output(msg)
    @out.write("#{msg}\n")
  end
end

你的考试变成......

out = StringIO.new
Foo.new(out)
Foo.something_cool
out.rewind.read.should eq("this is an artifact I want to test\n")