我正在使用RSpec来测试简单REPL的行为。除非输入是“退出”,否则REPL只是回应输入的内容,在这种情况下,它会终止循环。使用RSpec和线程测试Ruby中的REPL
为了避免悬挂测试跑步者,我在单独的线程内运行REPL方法。为了确保线程中的代码在我写预期之前已经执行完毕,我发现有必要包含一个简短的sleep
调用。如果我删除它,测试会间歇性失败,因为有时会在线程中的代码运行之前做出期望。
什么是构造代码和规范的好方法,以便我可以确定性地对REPL的行为进行期望,而不需要sleep
黑客?
下面是REPL类和规格:
class REPL
def initialize(stdin = $stdin, stdout = $stdout)
@stdin = stdin
@stdout = stdout
end
def run
@stdout.puts "Type exit to end the session."
loop do
@stdout.print "$ "
input = @stdin.gets.to_s.chomp.strip
break if input == "exit"
@stdout.puts(input)
end
end
end
describe REPL do
let(:stdin) { StringIO.new }
let(:stdout) { StringIO.new }
let!(:thread) { Thread.new { subject.run } }
subject { described_class.new(stdin, stdout) }
# Removing this before hook causes the examples to fail intermittently
before { sleep 0.01 }
after { thread.kill if thread.alive? }
it "prints a message on how to end the session" do
expect(stdout.string).to match(/end the session/)
end
it "prints a prompt for user input" do
expect(stdout.string).to match(/\$ /)
end
it "echoes input" do
stdin.puts("foo")
stdin.rewind
expect(stdout.string).to match(/foo/)
end
end
这给我带来了很长的路,但不幸的是我仍然有间歇性故障(并且在一个例子中仍然需要睡眠呼叫),因为我不能保证MRI在预期之前切换回到运行循环的线程以RSpec为例。 – 2013-05-01 08:03:18