我正在使用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