8

我有一个使用 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

4

3 回答 3

14

您可以创建一个管道并将其“读取端”分配给$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
于 2013-06-05T21:27:48.497 回答
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确实得到用户键入的内容。

虽然这是对您的问题的实际答案,但我不知道该怎么做 2.,我只知道如何在浏览器 ( watir-webdriver) 后面模仿用户,而不是在 shell 会话后面。

于 2013-06-05T20:01:32.387 回答
3

您可以注入 IO 依赖项。 gets读取自STDIN,即 class 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}"
于 2013-06-05T22:29:35.133 回答