如何在rspec中测试put

时间:2013-07-17 20:11:38

标签: rspec

我想要的是在命令行上运行ruby sayhello.rb,然后接收Hello from Rspec

我有这个:

class Hello
  def speak
    puts 'Hello from RSpec'
  end
end

hi = Hello.new #brings my object into existence
hi.speak

现在我想在rspec中编写一个测试来检查命令行输出实际上是“来自RSpec的Hello” 而不是“我喜欢Unix”

不工作。我目前在我的sayhello_spec.rb文件中有这个

require_relative 'sayhello.rb' #points to file so I can 'see' it

describe "sayhello.rb" do
  it "should say 'Hello from Rspec' when ran" do        
    STDOUT.should_receive(:puts).with('Hello from RSpec')    
  end
end

另外,我需要实际看看我的RSPEC中的测试应该是什么样的。

5 个答案:

答案 0 :(得分:16)

您在进入测试块之前执行代码,因此未达到预期。您需要在设置期望后运行测试块中的代码(例如,通过在require_relative语句之后移动STDOUT....语句),如下所示:

describe "sayhello.rb" do
  it "should say 'Hello from Rspec' when ran" do        
    STDOUT.should_receive(:puts).with('Hello from RSpec')
    require_relative 'sayhello.rb' #load/run the file 
  end
end

答案 1 :(得分:14)

根据以前的答案/评论,使用没有gem的新语法的解决方案如下所示:

describe "sayhello.rb" do
  it "should say 'Hello from Rspec' when run" do        
    expect(STDOUT).to receive(:puts).with('Hello from RSpec')
    require_relative 'sayhello.rb'  # load/run the file 
  end
end

答案 2 :(得分:14)

我认为最好的方法是在输出匹配器https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/output-matcher

中使用rspec build

例如, 这是你的班级

class MakeIt
  def awesome(text)
    puts "Awesome #{text}"
  end
end

和你的考试

describe MakeIt do
  describe '#awesome' do
    it 'prints awesome things' do
      expect do
        MakeIt.new.awesome('tests')
      end.to output('Awesome tests').to_stdout
    end

    it 'does not print not awesome things' do
      expect do
        MakeIt.new.awesome('tests')
      end.to_not output('Not awesome tests').to_stdout
    end
  end
end

很好,很干净,靠书!

答案 3 :(得分:12)

您可以使用Rails'active_support库来解决此问题,该库会添加capture方法:

require 'active_support/core_ext/kernel/reporting'
require_relative 'sayhello'

describe Hello do
  it "says 'Hello from RSpec' when ran" do
    output = capture(:stdout) do
      hi = Hello.new
      hi.speak
    end
    expect(output).to include 'Hello from RSpec'
  end
end

答案 4 :(得分:3)

与bswinnerton的回答有些类似,可以捕获puts输出,然后针对捕获的输出进行测试,而不必使用依赖于库的capture方法(有人提到的是在Rails中被弃用5)。

Ruby有一个名为$stdout的全局变量,默认情况下由常量STDOUT填充。 STDOUT是将数据发送到ruby进程的stdout流的(不确定" stream"是否是正确的术语)。基本上在一个天真的情况STDOUT.puts("foo")将导致" foo \ n"出现在终端窗口中。 $stdout.puts("foo")会做同样的事情,因为$stdout变量名称是指STDOUT ,除非您重新分配(此处为关键点)。最后puts("foo")$stdout.puts("foo")的语法糖。

然后,策略是将$stdout重新分配给您可以在运行代码后检查的本地IO实例,以查看是否来自RSpec"出现在其内容中。

这将如何运作:

describe "sayhello.rb" do
  it "should say 'Hello from Rspec' when ran" do        
    $stdout = StringIO.new

    # run the code
    # (a little funky; would prefer Hello.new.speak here but only changing one thing at a time)
    require_relative 'sayhello.rb' 

    $stdout.rewind   # IOs act like a tape so we gotta rewind before we play it back  

    expect($stdout.gets.strip).to eq('Hello from Rspec')
  end
end