Как обрабатывать интерактивный ввод с консоли, используя Cucumber или SpecFlow - PullRequest
1 голос
/ 03 января 2012

Этот вопрос относится к примеру взломщика кодов, найденному в книге RSpec. Смотрите код здесь: https://github.com/kristianmandrup/rspec-book-codebreaker/tree/master/features

Мне было интересно, разработал ли кто-нибудь полное решение для игры со взломом кода.

Мне интересно посмотреть, как проверить внешний цикл, который решает, должна ли игра продолжаться или нет.

Функциональность может выглядеть следующим образом

  • Вы нашли секретный код!
  • Хотите попробовать еще раз? : n
  • Прощайте

Если пользователь выбирает «y», то игра начинается снова. Мне интересно увидеть сценарии и определения шагов. Было бы что-то вроде:

Scenario: user finds secret code
Given the secret code is "1234" 
When I guess "1234" 
Then I should see "You found the secret code!" 
And I should see "Would you like to try again?"

Другой файл спецификаций:

Background: Found secret code
Given the secret code is "1234" 
And I guess "1234" 

Scenario: user chooses to quit the game
Given I see "Would you like to try again?" 
When I enter "n" 
Then I should see "Good-bye" 

Scenario: user chooses to continue with the game
Given I see "Would you like to try again?" 
When I enter "y" 
Then I should see "Enter guess:"

Как видно из ссылки выше, в настоящее время передается двойной (фиктивный) выходной объект. Весь вывод захватывается этим двойным значением, а затем используется в утверждениях. Вход немного отличается. Когда в приложении отображается сообщение «Хотите повторить попытку?», Тогда в зависимости от теста для ввода макета ввода требуется ответ «y» или «n». Возможно, это не тот путь?

Есть что-то похожее на имитацию пользователя, определение шага выглядит так:

When /^I guess "([^\"]*)"$/ do |guess|
@game.guess(guess)
end

Это текущий основной метод:

def generate_secret_code
    options = %w[1 2 3 4 5 6]
    (1..4).map { options.delete_at(rand(options.length))}.join
end
game = Codebreaker::Game.new(STDOUT)
secret_code = generate_secret_code
at_exit { puts "\n***\nThe secret code was: #{secret_code}\n***" }

game.start(secret_code)
while guess = gets.chomp
    game.guess(guess)
end

Внешний цикл был добавлен без каких-либо тестов. Я хотел бы знать, как иметь дело с gets.chomp - как я могу «издеваться» над этим поведением? Это как обрабатывать интерактивный ввод с консоли?

Я на самом деле использую SpecFlow и C #, если возможно, предоставлю решение для C #. Решение Ruby также может помочь ...

Спасибо

1 Ответ

0 голосов
/ 03 января 2012

Можно запустить консольное приложение и присоединить к нему стандартные потоки ввода и вывода. См. Пример в документации ProcessStartInfo.RedirectStandardInput.

Более чистый способ (который также ускорил бы тестирование, но не считался бы полным комплексным тестированием системы) - это несколько реструктурировать приложение, чтобы оно использовало обычные Stream объекты вместо Console.In и Console.Out; метод main() может передавать эти классы остальной части приложения. Затем ваши тесты могут напрямую вызывать другие методы и передавать MemoryStream объекты в качестве потоков ввода / вывода.

...