Thursday, March 25, 2010

Test with outside resources with stub or mock ::Ruby Best Practices

user inputに係るテスト
  1. StringIOによるスタブ
  2. flexmock libraryを使ったスタブ

tc_question.rb

require "test/unit"

require_relative "question"
require_relative "test_unit_extensions"
require "flexmock/test_unit"
#require "stringio"

class TestQuestion < Test::Unit::TestCase
  def setup
   # @input = StringIO.new
   # @output = StringIO.new
    @input = flexmock("input")
    @output = flexmock("output")
    @questioner = Questioner.new(@input, @output)
    @question = "Are you happy?"
  end

  %w(y Y YeS YES yes).each do |yes|
    must "return true when parsing #{yes}" do
      expect_output @question
      provide_input(yes)
      assert @questioner.ask(@question), "Expect #{yes} to be true"
    end
  end

  %w(n N no nO).each do |no|
    must "return false when parsing #{no}" do
      expect_output @question
      provide_input(no)
      assert ! @questioner.ask(@question), "Expect #{no} to be false"
    end
  end

  [["y", true],["n", false]].each do |input, state|
    must "conginue to ask for inpu until given #{input}" do
      %w(Yesterday North kittens).each do |i|
        expect_output @question
        provide_input(i)
        expect_output "I don't understand."
      end
      expect_output @question
      provide_input(input)
      assert_equal state, @questioner.ask(@question)
    end
  end


#  must "respond 'Good I'm Grad' when inquire_about_happiness gets 'yes'" do
#    def @questioner.ask(quesiotn); true; end
#    assert_equal "Good I'm Glad", @questioner.inquire_about_happiness
#  end
#
#  must "respond 'That's Too Bad' when inquire_about_happiness gets 'no'" do
#    def @questioner.ask(quesiotn); false; end
#    assert_equal "That's Too Bad", @questioner.inquire_about_happiness
#  end

  must "respond 'Good I'm Grad' when inquire_about_happiness gets 'yes'" do
    stubbed = flexmock(@questioner, :ask => true)
    assert_equal "Good I'm Glad", stubbed.inquire_about_happiness
  end

  must "respond 'That's Too Bad' when inquire_about_happiness gets 'no'" do
    stubbed = flexmock(@questioner, :ask => false)
    assert_equal "That's Too Bad", stubbed.inquire_about_happiness
  end

  def provide_input(string)
   # @input << string
   # @input.rewind
    @input.should_receive(:gets => string).once
  end

  def expect_output(string)
    # assert_equal string, @output.string
    @output.should_receive(:puts).with(string).once
  end
end


question.rb
class Questioner
  def initialize(_in=STDIN, out=STDOUT)
    @input = _in
    @output = out
  end

  def inquire_about_happiness
    ask("Are you happy?") ? "Good I'm Glad" : "That's Too Bad"
  end

  def ask(question)
    @output.puts question
    response = yes_or_no(@input.gets.chomp)
    response.nil? ? ask(question) : response
  end

  def yes_or_no(response)
    case response
    when /^y(es)?$/i
      true
    when /^no?$/i
      false
    else
      @output.puts "I don't understand."
      nil
    end
  end
end

if $0 == __FILE__
  qs = Questioner.new
  p qs.inquire_about_happiness
end



No comments: