Ошибка rspec 3, когда пользователю предлагается ввести данные
У меня есть код, который запрашивает пользователя для ввода, например:
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
Каков наилучший способ проверить этот метод?
2 ответа
Проблема в том, что 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
по умолчанию реализация респондента. В своем тесте вы можете легко предоставить респондент, который не требует вмешательства человека, просто передав блок, который возвращает строку.
Не уверен, что это лучший способ справиться с этим, но вы можете отправить 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