0

I have the following method in class QuestionList

def ask_all
    @questions.each do |question|
        question.ask
        @player.add_answer(gets.chomp)
    end
end

The questions have integer answers, and the answers do not have to be correct for this test - there simply just needs to be an integer number received and added to the list @player.answers with the following method in class Player

def add_answer(answer)
    @answers << answer
end

How can I simulate user input to the gets.chomp of QuestionList.ask_all when unit testing the method as so:

class QuestionListTest < Test::Unit::TestCase

    def setup
        ...
    end

    def test_ask_all
        #unit test for 'QuestionList.ask_all' here
    end

end
KOB
  • 4,084
  • 9
  • 44
  • 88
  • `@player.add_answer((1..10).to_a.sample)` – Aleksei Matiushkin Nov 17 '16 at 12:11
  • how do I implement that in a `< Test::Unit::TestCase` class though? – KOB Nov 17 '16 at 12:14
  • Obviously mock `@player#add_answer` with `return (1..10).to_a.sample`. – Aleksei Matiushkin Nov 17 '16 at 13:07
  • I'm still lost with how to implement that in my `test_ask_all` method? `@player.add_answer` adds the answer to a list and returns the list. So, in my test method, I would need something along the lines of `assert_equal([1], @questions.ask_all)`, but `ask_all` has the line `@player.add_answer(gets.chomp)` within it, so there is no way that `gets.chomp` can be executed in the test class and I don't see how to do what you are suggesting - that `ask_all` will be executed with the line `@player.add_answer((1..10).to_a.sample)` only when ran in the test class, but not when ran in the main program. – KOB Nov 17 '16 at 23:54
  • @mudasobwa I have added far more information to my OP – KOB Nov 18 '16 at 00:06

1 Answers1

1

1. Modify ask_all to be input-agnostic:

def ask_all
    @questions.each do |question|
        question.ask
        @player.add_answer(question.retrieve_answer)
    end
end

2. Modify Question class to have retrieve_answer method:

class Question
  def ask
    # even better, delegate this to some other class
    #  to make it possible to work with console,
    #  batches, whatever depending on settings
    print "Enter an answer >"
  end
  def retrieve_answer
    # for now it’s enough
    gets.chomp
  end
end

3. Mock Question class to “ask questions” not interactively:

class QuestionListTest < Test::Unit::TestCase

    def setup
      Question.define_method :ask do
        print "I am mock for prompting ... "
      end
      Question.define_method :retrieve_answer do
        # be aware of wrong input as well!
        [*(1..10), 'wrong input', ''].sample.tap do |answer|
          puts "mocked answer is #{answer}." 
        end
      end
    end

    def test_ask_all
      expect(ask_all).to match_array(...)
    end
end
Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160