RSPL을 사용하여 간단한 REPL의 동작을 테스트하고 있습니다. REPL은 입력이 "exit"가 아닌 한, 입력이 무엇 이던지 에코를 반복합니다.이 경우 입력은 루프를 종료합니다.RSpec 및 스레드로 REPL 테스트하기
테스트 러너가 멈추지 않게하려면 별도의 스레드 안에 REPL 메소드를 실행하고 있습니다. 스레드에 대한 기대치를 쓰기 전에 스레드의 코드가 실행되었는지 확인하려면 간단한 sleep
호출을 포함시켜야합니다. 제거하면 테스트가 일시적으로 실패합니다. 왜냐하면 스레드의 코드가 실행되기 전에 때로는 기대가 이루어지기 때문입니다.
sleep
해킹없이 REPL의 행동을 결정 론적으로 기대할 수 있도록 코드와 스펙을 구조화하는 좋은 방법은 무엇입니까? 나는이 같은 상황에 대한 running?
가드를 사용했습니다
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 예제에서 만들어졌다. –