RESOLVED
Question 1: I want to write a test for file_choice_reader in the following class.
The class prints a list of files of certain types to command line and lets the user choose one by typing in the index number.
class File_chooser
#shortened for readability
def file_choice_suggester
file_list = file_list_generator
if file_list.count > 0
file_list.each_with_index do |file, index|
puts index.to_s + ' ' + file
end
else
puts 'Neither .fcv nor .tmpl nor .ipa nor .apf files in directory.'
end
file_list
end
def file_choice_reader
unless File.exists? 'Cookie.txt'
file_list = file_choice_suggester
puts 'Choose file by typing index number!'
chosen_file = STDIN.gets.chomp
if /[^0-9]/.match(chosen_file) || chosen_file.to_i >= file_list.count
abort ('No valid index number.')
else
chosen_file = chosen_file.to_i
end
cookie_writer( file_list[chosen_file].to_s )
system 'cls'
puts 'You chose file: ' + file_list[chosen_file].to_s
path_and_file = file_list[chosen_file].to_s
else
self.hints_hash = hints_hash.merge( 'cookie_del' => '* Change file by typing command: del Cookie.txt *' )
pre_chosen_file = File.read('Cookie.txt')
path_and_file = pre_chosen_file.chomp.to_s
end
path_and_file
end
end
My test looks like this (I get prompted to type in the index number but it still says that the output is ""):
class TestFile_chooser < MiniTest::Unit::TestCase
def setup
@file_chooser = File_chooser.new
end
def test_file_choice_reader_produces_confirmation_output
assert_output( /You chose file/ ) { @file_chooser.file_choice_reader }
end
end
The output of file_choice_reader is always "". How can I add the sequence of getting user input and /then/ measuring output?
Question 2: This is a short question. The same test class as above also contains
def test_file_choice_suggester_produces_output
assert_output( /apf|fcv|tmpl|ipa/ ) { @file_chooser.file_choice_suggester }
end
This test passes. But it leaves me with "1 runs, 2 assertions". That leaves me puzzled. How can 1 test in 1 run produce 2 (??) assertions?
I would be very glad about help. The minitest discussion on the internet doesn't seem to cover these things. Maybe it is too fundamental?
(I am grateful for all other remarks about the code in comments, too. Thank you for helping.)
UPDATE (Question 1)
With the help of the reply below, my newest version of the test using the example in http://www.ruby-doc.org/core-2.1.5/Module.html
@file_chooser.instance_eval do
self.create_method( :puts ) {|arg| printed = arg}
end
The test ran without error ... BUT ... it STILL tells me: "Failed refutation. No message given."
Thanks for the help so far! Thanks also for all hints how to figure it out.
[Adding here for code is difficult to read in comments.]
UPDATE 2 (Question 1)
I followed the advice on a different question to explicitely require the minitest gem. I put this above my testfile code:
require 'rubygems'
gem 'minitest'
require 'minitest/autorun'
require_relative 'falcon'
(If this is redundant please let me know.)
The following testcode now neither produces an error nor a failure anymore:
def test_file_choice_suggester_produces_output
assert_output( /apf|fcv|tmpl|ipa/ ) { @file_chooser.file_choice_suggester }
end
Thanks all for your help!
For #1:
One approach could be to stub out the IO object that your test is using by overriding the
puts
method. The other would be to refactor your design so that your methods are smaller and easier to test.The
puts
override would go something like this:In your test:
Alternatively, you could run an expectation on the $STDOUT object to make sure it gets the correct call (see Mocha for Ruby)