Ruby minitest тестовый вывод метода, который требует пользовательского ввода

РЕШЕНО


Вопрос 1: Я хочу написать тест для file_choice_reader в следующем классе.

Класс выводит список файлов определенных типов в командную строку и позволяет пользователю выбрать один из них, введя порядковый номер.

class File_chooser

  #shortened for readability

  def file_choice_suggester
    file_list = file_list_generator
    if file_list.count > 0
      file_list.each_with_index do |file, index|
        puts index.to_s + ' ' + file
      end
    else 
      puts 'Neither .fcv nor .tmpl nor .ipa nor .apf files in directory.'  
    end
    file_list
  end

  def file_choice_reader
    unless File.exists? 'Cookie.txt'
      file_list = file_choice_suggester
      puts 'Choose file by typing index number!'
      chosen_file = STDIN.gets.chomp
      if /[^0-9]/.match(chosen_file) || chosen_file.to_i >= file_list.count
        abort ('No valid index number.')
      else 
        chosen_file = chosen_file.to_i
      end
      cookie_writer(  file_list[chosen_file].to_s )
      system 'cls'
      puts 'You chose file: ' + file_list[chosen_file].to_s
      path_and_file = file_list[chosen_file].to_s
    else
      self.hints_hash = hints_hash.merge( 'cookie_del' => '* Change file by typing command: del Cookie.txt *' )
      pre_chosen_file = File.read('Cookie.txt')
      path_and_file = pre_chosen_file.chomp.to_s
    end
    path_and_file
  end

end

Мой тест выглядит так (мне предлагается ввести номер индекса, но он все еще говорит, что вывод «»):

class TestFile_chooser < MiniTest::Unit::TestCase 
  def setup
    @file_chooser = File_chooser.new
  end

  def test_file_choice_reader_produces_confirmation_output
    assert_output( /You chose file/ ) { @file_chooser.file_choice_reader }
  end 
end

Вывод file_choice_reader всегда "". Как я могу добавить последовательность получения пользовательского ввода и/затем/измерения вывода?

Вопрос 2: Это короткий вопрос. Тот же тестовый класс, что и выше, также содержит

  def test_file_choice_suggester_produces_output
    assert_output( /apf|fcv|tmpl|ipa/ ) {  @file_chooser.file_choice_suggester }
  end 

Этот тест проходит. Но это оставляет меня с «1 запуском, 2 утверждениями». Это оставляет меня озадаченным. Как 1 тест за 1 прогон может дать 2 (??) утверждения?

Буду очень рад помощи. Обсуждение minitest в Интернете, кажется, не охватывает эти вещи. Может быть, это слишком фундаментально?

(Я также благодарен за все другие замечания о коде в комментариях. Спасибо за помощь.)


ОБНОВЛЕНИЕ (Вопрос 1)

С помощью приведенного ниже ответа моя новейшая версия теста с использованием примера в http://www.ruby-doc.org/core-2.1.5/Module.html

@file_chooser.instance_eval do 
  self.create_method( :puts ) {|arg| printed = arg} 
end

Тест прошел без ошибок... НО... мне ВСЕ ЕЩЕ пишет: "Опровержение не удалось. Сообщение не выдано".

Спасибо за помощь! Спасибо также за все подсказки, как это понять.

[Добавление сюда кода трудно прочитать в комментариях.]


ОБНОВЛЕНИЕ 2 (вопрос 1)

Я последовал совету по другому вопросу, чтобы явно потребовать драгоценный камень minitest. Я поместил это выше кода моего тестового файла:

require 'rubygems'
gem 'minitest'
require 'minitest/autorun'
require_relative 'falcon'

(Если это избыточно, пожалуйста, дайте мне знать.)

Следующий тестовый код больше не выдает ни ошибки, ни сбоя:

  def test_file_choice_suggester_produces_output
    assert_output( /apf|fcv|tmpl|ipa/ ) {  @file_chooser.file_choice_suggester }
  end 

Спасибо всем за вашу помощь!


person enahel    schedule 11.11.2014    source источник
comment
# 2 это может быть связано с методом assert_output, который делает несколько утверждений. Или если у вас есть оба этих теста в одном файле.   -  person Josh Bodah    schedule 12.11.2014
comment
Что касается стиля, я рекомендую руководство по стилю GitHub: github.com/styleguide/ruby.   -  person Josh Bodah    schedule 12.11.2014
comment
# 1 Не уверен, в чем именно заключается вопрос, но должен ли он заглушить пользовательский ввод или передать входной поток в качестве аргумента или что-то в этом роде.   -  person Josh Bodah    schedule 12.11.2014
comment
Благодарю вас! Вопрос в том, как написать тест, который гарантирует, что мой пользователь получит подтверждающее сообщение. Вывод не является прямым выводом метода, а появляется только после ввода пользователем данных в sdtin. Тест в настоящее время говорит мне, что метод выводит пустую строку. Это не так после пользовательского ввода. Как мне нужно написать тест? (Надеюсь, это понятнее.)   -  person enahel    schedule 12.11.2014


Ответы (1)


Для №1:

Один из подходов может состоять в том, чтобы заглушить объект ввода-вывода, который использует ваш тест, путем переопределения метода puts. Другим будет рефакторинг вашего дизайна, чтобы ваши методы были меньше и их было легче тестировать.

Переопределение puts будет выглядеть примерно так:

В вашем тесте:

@file_chooser = File_chooser.new
printed = nil
@file_chooser.instance_eval do
  # Open up the instance and stub out the puts method to save to a local variable
  define_method :puts, Proc.new {|arg| printed = arg}
end
# Run code
refute printed.nil?

В качестве альтернативы вы можете выполнить ожидание для объекта $STDOUT, чтобы убедиться, что он получает правильный вызов (см. Mocha для Ruby).

person Josh Bodah    schedule 12.11.2014
comment
Благодарю вас! К сожалению, это не работает для меня. Сообщение об ошибке: falcon_test.rb:90: синтаксическая ошибка, неожиданный '{', ожидание ключевого слова end define_method, :puts {|arg| напечатано = arg} ^ falcon_test.rb:90: синтаксическая ошибка, неожиданный '}', ожидание ключевого слова falcon_test.rb:116: синтаксическая ошибка, неожиданный $end, ожидание ключевого_конца - person enahel; 13.11.2014
comment
Я помещаю код в def test .... end. Не уверен, что я делаю неправильно. Спасибо за ответ. - person enahel; 13.11.2014
comment
Извините, я перепутал синтаксис. Попробуй это сейчас - person Josh Bodah; 14.11.2014
comment
Благодарю вас! После прочтения о том, что define_method является приватным, и повторения взлома на этой странице ruby- doc.org/core-2.1.5/Module.html тест прошел без ошибок: @file_chooser.instance_eval do self.create_method( :puts ) {|arg| print = arg} end ... НО ... он ВСЕ ЕЩЕ говорит мне, что мой вывод: In stdout. Ожидается, что /apf|fcv|tmpl|ipa/ будет соответствовать . Спасибо до сих пор. Я определенно чему-то научился. Благодарен за все подсказки, как это понять! - person enahel; 15.11.2014
comment
Извините, перепутал сообщения об ошибках. Сообщение: Неудачное опровержение. Сообщение не передано. - person enahel; 15.11.2014
comment
Выше я добавил код, который теперь работает. Похоже, моя проблема была связана с тем, что я не вызывал драгоценный камень minitest явным образом. Спасибо за вашу помощь. - person enahel; 01.12.2014