我想要的是在命令行上运行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中的测试应该是什么样的。
答案 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