3
\$\begingroup\$

I'm trying to test an elevator simulator program that runs in the console and requires user interaction. At the moment, my tests look like this:

gem 'minitest', '>= 5.0.0'
require 'minitest/spec'
require 'minitest/autorun'
require_relative 'elevator'

class SingleFloorElevator < Elevator
  @@moves = ["2", "N"].each
  def get_input; @@moves.next end
end

class MultiFloorElevator < Elevator
  @@moves = ["2", "Y", "7", "Y", "4", "N"].each
  def get_input; @@moves.next end
end

class InvalidElevetorOne < Elevator
  @@moves = ["-2", "2"].each
  def get_input; @@moves.next end
end

class InvalidElevatorTwo < Elevator
  @@moves = ["2000", "5"].each
  def get_input; @@moves.next end
end

class ElevatorTest < MiniTest::Test
  def test_can_accept_and_move_to_floor
    e = SingleFloorElevator.new
    e.run
    assert_equal(e.current_floor, 2)
  end

  def test_can_change_direction
    e = MultiFloorElevator.new
    e.run
    assert_equal(e.going_down, true)
    assert_equal(e.going_up, false)
  end

  describe "it can maintain a list of floor numbers" do
    it "cannot travel below the ground floor" do
      e = InvalidElevetorOne.new
      e.enter_floor
      assert_equal(e.floors.size, 1)
      assert_equal(e.floors, [2])
    end

    it "cannot travel higher than the top floor" do
      e = InvalidElevatorTwo.new
      e.enter_floor
      assert_equal(e.floors.size, 1)
      assert_equal(e.floors, [5])
    end
  end
end

As you can see, I'm overriding the Elevator class (more important the get_input method which grabs user input from the console) multiple times according to what I need to test. It all works perfectly fine but I was wondering if there was a tidier way of doing things?

\$\endgroup\$
2
\$\begingroup\$

I kind of wish you had posted the elevator class as well, but it's kind of interesting how you much you can tell about the CUT (code under test) from looking at the just the tests themselves.

First, your elevator shouldn't be responsible for getting what floor it should go to from the user. Your program should tell it where to go. If you inverted control, you wouldn't have to subclass the code under test in order to test it.

Which brings me to my second point...

If you have to mock the CUT, you're no longer actually testing anything. You can't have confidence that your real class is going to behave as you expect it to, because you've very explicitly changed how it behaves. You're not testing your elevator. You're testing your mock elevators, which is no test at all.

Sure, you are testing the elevator. I know that, but certainly, this class has too many responsibilities. It shouldn't be getting user input from the console. How could you possibly reuse the elevator class in a GUI application later?

\$\endgroup\$
1
  • \$\begingroup\$ Ah, I didn't think of that. Thanks for the advice, I'll refactor and maybe testing will be easier after that! \$\endgroup\$ – SoSimple Nov 26 '15 at 9:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.