Тестовая программа, которая запускается с пользовательским вводом из консоли

Я пишу тесты для системы, моделирующей лифт. Например, я хочу проверить, что лифт может менять направление и двигаться на указанный этаж.

У меня есть следующие методы:

def initialize
  @current_floor = 0
  @requested_floor = 0
end
def get_value
  gets.chomp
end
def arrival
  print "Enter floor number: "
  @requested_floor = get_value
  # only proceed if user entered an integer
  if validate_floor_number(@requested_floor)
    @requested_floor = @requested_floor.to_i
    move
  else
    arrival
  end
end
def move
  msg = ""
  @current_floor < @requested_floor ? msg = "Going Up!" : msg = "Going Down"
  puts msg
  @current_floor = @requested_floor
  next_move
end
def next_move
  puts "Do you want to go to another floor? Y/N"
  another_floor = (get_value).upcase
  another_floor == 'N' ? final_destination : arrival
end

Я запускаю программу, вызывая Elevator.new.arrival. Чтобы убедиться, что лифт изменил направление, мне нужно сохранить значение @current_floor во временной переменной, а затем проверить, изменилось ли это значение после вызова move.

Я тестирую ввод с консоли с помощью канала ввода-вывода благодаря ответам в этот вопрос, но я не уверен, как применить эти знания к взаимодействию с пользователем, которое является частью метода.

Как я могу смоделировать программу, работающую с самого начала (Elevator.new.arrival), через метод move и остановить ее там, чтобы я мог проверить значение @current_floor — и все это без запуска самой программы и использования канала ввода-вывода для имитации взаимодействия с пользователем?

У меня есть ощущение, что я мог неправильно подойти к разработке программы. Если кто-нибудь может даже указать мне правильное направление для решения этой проблемы, я был бы признателен.

Изменить

В соответствии с предложениями Wand Maker я написал тест следующим образом:

  describe "checks that the elevator can change directions" do
    before do
      moves = [3, 'Y', 5, 'Y', 2, 'Y', 7, 'N']
      def get_value; moves.next end
    end

    it "should stop on floor 7" do
      Elevator.new.arrival
      assert_equal(@current_floor, 7)
    end
  end

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


person SoSimple    schedule 22.11.2015    source источник
comment
Вы уверены, что перезаписали метод экземпляра класса Elevator get_value? Возможно, вам следует открыть класс и перезаписать его.   -  person Wand Maker    schedule 22.11.2015
comment
Я не уверен на 100%, что вы имеете в виду? Я не знаю другого способа переопределить метод из тестового файла, кроме того, который был предложен в том вопросе, на который вы ссылались (см. отредактированный ответ).   -  person SoSimple    schedule 22.11.2015
comment
я обновил свой ответ   -  person Wand Maker    schedule 22.11.2015


Ответы (2)


Как показано в этом ответе, вы можете переопределить getvalue для подачи пользовательского ввода.

Вот полный код, который работает без фактического использования gets. Пришлось добавить пару отсутствующих методов — validate_floor_number и final_destination:

require 'minitest/autorun'

class Elevator
  attr_accessor :current_floor

  def initialize
    @current_floor = 0
    @requested_floor = 0
    #@last_floor = false
  end

  def get_value
    gets.chomp
  end

  def validate_floor_number(v)
    v.to_i rescue false
  end

  def arrival
    print "Enter floor number: "
    @requested_floor = get_value

    # only proceed if user entered an integer
    if validate_floor_number(@requested_floor)
      @requested_floor = @requested_floor.to_i
      move
    else
      arrival
    end
  end

  def move
    msg = ""
    @current_floor < @requested_floor ? msg = "Going Up!" : msg = "Going Down"
    puts msg
    @current_floor = @requested_floor
    next_move
  end

  def final_destination 
    puts "Reached your floor"
  end

  def next_move
    puts "Do you want to go to another floor? Y/N"
    another_floor = (get_value).upcase
    another_floor == 'N' ? final_destination : arrival
  end

 end 

 describe "checks that the elevator can change directions" do
    before do
      class Elevator
          @@moves = [3, 'Y', 5, 'Y', 2, 'Y', 7, 'N'].each
          def get_value; @@moves.next end
      end
    end

    it "should stop on floor 7" do
      e = Elevator.new
      e.arrival
      assert_equal(e.current_floor, 7)
    end
 end

Вывод вышеуказанной программы:

Run options: --seed 2561

# Running:

Enter floor number: Going Up!
Do you want to go to another floor? Y/N
Enter floor number: Going Up!
Do you want to go to another floor? Y/N
Enter floor number: Going Down
Do you want to go to another floor? Y/N
Enter floor number: Going Up!
Do you want to go to another floor? Y/N
Reached your floor
.

Finished in 0.001334s, 749.4982 runs/s, 749.4982 assertions/s.

1 runs, 1 assertions, 0 failures, 0 errors, 0 skips
[Finished in 0.3s]
person Wand Maker    schedule 22.11.2015
comment
Я пытался реализовать ваши предложения (см. обновленный вопрос), но я думаю, что все еще что-то упускаю? Когда я запускаю свой тестовый файл, мне все еще предлагается ввести данные от пользователя. - person SoSimple; 22.11.2015
comment
Хорошо, я обновил ответ на основе вашего обновленного вопроса. - person Wand Maker; 22.11.2015
comment
Просто хочу еще раз проверить, нужно ли мне переопределять метод прибытия в тестовом файле? Я получаю сообщение об ошибке: undefined method 'arrival' for #<ElevatorTest::Elevator:0x000000021ae198> - может ли это быть синтаксической ошибкой с моей стороны? - person SoSimple; 22.11.2015
comment
Я не уверен, как вы организовали свою версию кода, но если вы скопируете / вставите приведенный выше код в файл .rb, он будет работать без ошибок. - person Wand Maker; 22.11.2015
comment
Да, ваш код работает нормально, никаких проблем, но у меня есть тесты в отдельном файле в той же папке. Я действительно хотел бы сохранить это таким образом для удобства использования. Большое спасибо за вашу помощь, но я думаю, что есть только одна последняя проблема - @current_floor все еще не читается. Это дает мне еще одну ошибку неопределенного метода даже с добавленным вами attr_accessor. Я пытался добавить @@current_floor = 0 (а также просто обычную переменную экземпляра) в переопределенный класс Elevator в тестовом файле, но это не помогает. - person SoSimple; 22.11.2015
comment
При доступе к переменной экземпляра извне класса вам нужно использовать синтаксис object.instance_var_name для доступа к переменным экземпляра — надеюсь, вы делаете это вместо прямого использования `@current_floor. - person Wand Maker; 22.11.2015
comment
Я добавил еще один attr_accessor в переопределенный класс в тестовом наборе (это неправильно?), но тест не проходит, потому что e.current_floor возвращает nil, поэтому я думаю, что мне нужно полностью переопределить методы прибытия, перемещения и next_move в test_suite ? Я ошибаюсь, думая об этом, или это правильный путь? - person SoSimple; 22.11.2015
comment
Я не думаю, что так много методов нужно переопределять для тестируемости. Ваш код может иметь некоторые недостатки. Надеюсь, ты разберешься. - person Wand Maker; 22.11.2015

Это ответ на эту часть вашего вопроса: Как я могу смоделировать программу, работающую с самого начала (Elevator.new.arrival) с помощью метода перемещения, и остановить ее там, чтобы я мог проверить значение @ текущий_этаж?

  1. Установить покабаг: gem install byebug
  2. Требовать это в вашем файле: require 'byebug'
  3. Добавьте команду byebug там, где вы хотите остановить свою программу, например, в начале move (см. код в конце поста)
  4. Вы попадаете в оболочку и можете просмотреть все, например @current_floor, набрав его, или экземпляр, используя self
  5. Если вы хотите продолжить, нажмите CTRL+D, и программа продолжится (с любыми изменениями, которые вы, возможно, сделали)

Это должно помочь вам отладить его.

def move
  byebug # <-- program will stop here
  msg = ""
  @current_floor < @requested_floor ? msg = "Going Up!" : msg = "Going Down"
  puts msg
  @current_floor = @requested_floor
  next_move
end
person Markus    schedule 22.11.2015