我有要求用户输入的代码,例如:
class Foo
def prompt_for_foobar
puts "where is the foobar?"
gets.chomp
end
end
我想测试我的应用程序是在询问“foobar在哪里?”。我的测试将通过评论'gets.chomp'。但这是必要的,我尝试的其他任何事情都给了我一个Errno :: ENOENT:错误。
it "should prompt user" do
console = Foo.new
request = "where is the foobar?"
expect { console.prompt_for_foobar }.to output(request).to_stdout
end
测试此方法的最佳方法是什么?
答案 0 :(得分:0)
不确定这是否是处理此问题的最佳方式,但您可以将puts
和gets
发送至STDOUT
和STDIN
。
class Foo
def prompt_for_foobar
STDOUT.puts "where is the foobar?"
STDIN.gets.chomp
end
end
然后,测试STDIN
收到带有您所需对象的puts
条消息。
describe Foo do
let(:foo) { Foo.new }
before(:each) do
allow(STDIN).to receive(:gets) { "user input" }
end
describe "#prompt_for_foobar" do
it "prompts the user" do
expect(STDOUT).to receive(:puts).with("where is the foobar?")
foo.prompt_for_foobar
end
it "returns input from the user" do
allow(STDOUT).to receive(:puts)
expect(foo.prompt_for_foobar).to eq "user input"
end
end
end
答案 1 :(得分:0)
问题是gets
是一种强制人类交互的方法(至少在RSpec的上下文中,stdin没有连接到另一个进程的管道),但是自动化测试工具的全部要点像RSpec一样,能够在不涉及人为干预的情况下运行测试。
因此,我建议您依赖于实现特定接口的协作者对象,而不是直接依赖于gets
,在测试环境中,您可以提供该接口的实现,没有人工交互的响应,在其他环境中,它可以使用gets
来提供响应。这里最简单的协作者界面可能是一个proc(它们非常适合这种事情!),所以你可以做到以下几点:
class Foo
def prompt_for_foobar(&responder)
responder ||= lambda { gets }
puts "where is the foobar?"
responder.call.chomp
end
end
RSpec.describe Foo do
it 'prompts the user to respond' do
expect { Foo.new.prompt_for_foobar { "" } }.to output(/where is the foobar/).to_stdout
end
it "returns the responder's response" do
expect(Foo.new.prompt_for_foobar { "response" }).to eq("response")
end
end
请注意prompt_for_foobar
不再直接调用gets
;相反,它委派了对responder
合作者的回复的责任。默认情况下,如果未提供响应者,则使用gets
作为响应者的默认实现。在您的测试中,您可以通过传递返回字符串的块来轻松提供不需要人工交互的响应者。