35

我想做的是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 中编写一个测试来检查命令行输出实际上是“Hello from RSpec”而不是“我喜欢 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 中实际查看测试应该是什么样子。

4

5 回答 5

31

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

例如,这是你的班级

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

漂亮,干净,书本!

于 2016-07-14T15:03:10.290 回答
16

根据之前的答案/评论,使用没有 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
于 2015-05-20T07:24:15.490 回答
15

您在进入测试块之前执行代码,因此没有达到预期。您需要在设置期望后(例如通过将语句移到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
于 2013-07-17T20:27:02.547 回答
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
于 2014-01-09T16:02:24.533 回答
3

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

Ruby 有一个名为的全局变量$stdout,默认情况下由常量填充STDOUTSTDOUT是将数据发送到 ruby​​ 进程的标准输出流的那个(不确定“流”是否是正确的术语)。基本上在幼稚的情况下STDOUT.puts("foo")会导致“foo\n”出现在您的终端窗口中。 $stdout.puts("foo")会做同样的事情,因为$stdout变量名是指STDOUT 除非你重新分配它(这里的关键点)。最后puts("foo")$stdout.puts("foo").

然后的策略是重新分配$stdout给本地IO实例,您可以在运行代码后检查该实例,以查看“Hello from 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
于 2016-01-07T23:25:02.120 回答