2013-06-05 15 views
7

mam prostą funkcją użyciu gets.chomp tak:Jak przetestować funkcję z gets.chomp w nim?

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

Chciałbym przetestować go przy użyciu ruby „s wbudowane w TestCase pakietu tak:

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

Problem polega na tym, kiedy przeprowadzę ten test, test gets.chomp zatrzymuje test, ponieważ potrzebuje go wprowadzić. Czy istnieje sposób, w jaki mogę symulować dane wejściowe użytkownika przy użyciu tylko ruby?

Odpowiedz

7

najpierw oddzielić 2 obawy metody:

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 

A potem przetestować drugi oddzielnie.

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 

Co do pierwszego, można

  1. przetestować go ręcznie i polegać, że nie złamie (zalecane podejście TDD nie jest religią).
  2. Zdobądź sporną wersję omawianej powłoki i zmuś ją do naśladowania, a następnie porównaj , czy w rzeczywistości get_action dostaje to, co użytkownik wpisze.

Chociaż jest to praktyczne rozwiązanie do Twojego problemu, nie wiem jak to zrobić 2., wiem tylko, jak naśladować użytkownika za pomocą przeglądarki (watir-webdriver), a nie za sesję powłoki.

12

Można utworzyć pipe i przypisać jego "koniec do przeczytania" do $stdin. Zapisywanie do "końca zapisu" rury, symuluje wprowadzanie danych przez użytkownika.

Oto przykład z odrobiną metody pomocnika with_stdin o powołaniu rury:

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

thnaks do tego 'IO.pipe', nauczył mnie czegoś tam. –

+0

Dzięki, polubiłeś podejście! –

3

Można wstrzyknąć zależność IO. gets czyta się z STDIN, która jest klasą IO. Jeśli wstrzykniesz kolejny obiekt IO do swojej klasy, w testach możesz użyć StringIO. Coś takiego:

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 

Testy:

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 

Pozwala to klasa interakcję z dowolnego strumienia IO (TTY, plików, sieci, itp).

na używanie go w konsoli w kodzie produkcji, przechodzą w STDIN i STDOUT:

require 'whatever' 

whatever = Whatever.new STDIN, STDOUT 
whatever.welcome_user 

puts "Your action was #{whatever.action}" 
Powiązane problemy