Come posso testare una funzione con gets.chomp?

Ho una semplice funzione usando gets.chomp in questo modo:

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

Mi piacerebbe testarlo usando la suite di TestCase integrata in TestCase come questa:

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

Il problema è che quando gets.chomp quel test, gets.chomp interrompe il test perché ha bisogno che l’utente inserisca qualcosa. C’è un modo per simulare gli input dell’utente usando solo ruby ?

Per prima cosa separa le 2 preoccupazioni del metodo:

 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 

E poi testare il secondo separatamente.

 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 

Per quanto riguarda il primo, puoi

  1. Provalo a mano e contati che non si romperà (approccio raccomandato, TDD non è una religione).
  2. Ottieni la versione sovvertita della shell in questione e get_action imitare l’utente, e confronta se get_action ottiene effettivamente ciò che l’utente digita.

Mentre questa è una risposta pratica al tuo problema, non so come fare 2., so solo come imitare l’utente dietro il browser ( watir-webdriver ) e non dietro la shell session.

Potresti creare una pipe e assegnare la sua “read end” a $stdin . Scrivendo alla “fine scrittura” del tubo, simula l’input dell’utente.

Ecco un esempio con un piccolo metodo di supporto with_stdin per l’impostazione del pipe:

 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 

Si potrebbe iniettare la dipendenza IO. gets letture da STDIN , che è class IO . Se si inserisce un altro object IO nella class, è ansible utilizzare StringIO nei test. Qualcosa come questo:

 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 

test:

 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 

Ciò consente alla class di interagire con qualsiasi stream IO (TTY, file, rete, ecc.).

Per usarlo sulla console nel codice di produzione, passare in STDIN e STDOUT :

 require 'whatever' whatever = Whatever.new STDIN, STDOUT whatever.welcome_user puts "Your action was #{whatever.action}"