如何使用gets.chomp测试函数?

时间:2013-06-05 19:53:46

标签: ruby unit-testing shell testing

我有一个使用gets.chomp这样的简单函数:

def welcome_user
   puts "Welcome! What would you like to do?"
   action = gets.chomp
end 

我想使用ruby内置的TestCase套件对其进行测试,如下所示:

class ViewTest < Test::Unit::TestCase
   def test_welcome
      welcome_user      
   end 
end 

问题是,当我运行该测试时,gets.chomp会停止测试,因为它需要用户输入某些内容。有没有办法只使用ruby模拟用户输入?

3 个答案:

答案 0 :(得分:13)

您可以创建pipe并将其“读取结束”分配给$stdin。写入管道的“写入结束”然后模拟用户输入。

这是一个用于设置管道的小辅助方法with_stdin的示例:

require 'test/unit'

class View
  def read_user_input
    gets.chomp
  end
end

class ViewTest < Test::Unit::TestCase
  def test_read_user_input
    with_stdin do |user|
      user.puts "user input"
      assert_equal(View.new.read_user_input, "user input")
    end
  end

  def with_stdin
    stdin = $stdin             # remember $stdin
    $stdin, write = IO.pipe    # create pipe assigning its "read end" to $stdin
    yield write                # pass pipe's "write end" to block
  ensure
    write.close                # close pipe
    $stdin = stdin             # restore $stdin
  end
end

答案 1 :(得分:7)

您首先要分离方法的两个问题:

def get_action
  gets.chomp
end

def welcome_user
  puts "Welcome to Jamaica and have a nice day!"
  action = get_action
  return "Required action was #{action}."
end

然后你分别测试第二个。

require 'minitest/spec'
require 'minitest/autorun'

describe "Welcoming users" do
  before do
    def get_action; "test string" end
  end

  it "should work" do
    welcome_user.must_equal "Required action was test string."
  end
end

至于第一个,你可以

  1. 手工测试并依赖它不会破坏(推荐方法,TDD不是宗教信仰)。
  2. 获取有问题的shell的颠覆版本并使其模仿用户,并进行比较 是否get_action确实得到了用户输入的内容。
  3. 虽然这是对你的问题的实际答案,但我不知道如何做2.我只知道如何模仿浏览器后面的用户(watir-webdriver)而不是shell会话后面。

答案 2 :(得分:3)

您可以注入IO依赖项。 getsSTDIN读取,即IO类。如果您在课程中注入另一个IO对象,则可以在测试中使用StringIO。像这样:

class Whatever
  attr_reader :action

  def initialize(input_stream, output_stream)
    @input_stream = input_stream
    @output_stream = output_stream
  end

  def welcome_user
    @output_stream.puts "Welcome! What would you like to do?"
    @action = get_input
  end

private

  def get_input
    @input_stream.gets.chomp
  end

end

试验:

require 'test/unit'
require 'stringio'
require 'whatever'

class WhateverTest < Test::Unit::TestCase
  def test_welcome_user
    input = StringIO.new("something\n")
    output = StringIO.new
    whatever = Whatever.new(input, output)

    whatever.welcome_user

    assert_equal "Welcome! What would you like to do?\n", output.string
    assert_equal "something", whatever.action
  end
end

这允许您的类与任何IO流(TTY,文件,网络等)进行交互。

要在生产代码中的控制台上使用它,请传入STDINSTDOUT

require 'whatever'

whatever = Whatever.new STDIN, STDOUT
whatever.welcome_user

puts "Your action was #{whatever.action}"