TStanley has asked for the wisdom of the Perl Monks concerning the following question:

I think the time has finally come where I add another set of tests to the Games::QuizTaker module to test a function that is completely untested in the current framework. Oddly enough, the function in question is the "test" function which prints out the questions of the quiz and waits for the input of an answer, which it then checks and reports back as to whether it is correct or incorrect.

Since this entire function is an interactive one, how would I go about implementing a decent test to cover this part of the module? As always, I'm merely looking for suggestions/alternatives. The test function of the module is below:
sub test{ my $self=shift; my $Answer_Sep=$self->get_AnswerDelimiter; my $Max=$self->get_MaxQuestions; my ($answer,$key,$line,$question_answer); my $question_number=1; my $number_correct=0; my $asep=qq"\\$Answer_Sep"; system(($^O eq "MSWin32"?'cls':'clear')); print"\n"; while($question_number<=$Max){ $key=shift @Randoms; print"Question Number $question_number\n"; foreach $line(@{$$questions{$key}}){ print wrap("","","$line\n"); } print"Your Answer: "; $answer=<STDIN>; chomp($answer); $answer=uc($answer); $question_answer=$Test_Answers{$key}; chomp($question_answer); $question_answer=uc $question_answer; my $ln=length($question_answer); if($ln>1){ if($question_answer!~/$Answer_Sep/){ warn"Answer_Delimiter doesn't match internally"; } if($Answer_Sep eq " "){ }else{ $question_answer=~s/$asep/ /; } $question_answer=$self->answer_sort($question_answer); $answer=$self->answer_sort($answer); } # print "My Answer: $answer\n"; # print "Test Answer: $question_answer\n"; if("$answer" eq "$question_answer"){ print"That is correct!!\n\n"; $question_number++; $number_correct++; }else{ print"That is incorrect!!\n"; print"The correct answer is $question_answer.\n\n"; $question_number++; } } my $Final=$self->get_Score; if(defined $Final){ $self->Final($number_correct,$Max); return; }else{ return; } }

People sleep peaceably in their beds at night only because rough men stand ready to do violence on their behalf. -- George Orwell

Replies are listed 'Best First'.
Re: Writing a module test
by tirwhan (Abbot) on Jun 09, 2007 at 13:20 UTC

    I'd probably refactor QuizTaker to add a Games::QuizTaker::IO module which implements the extremely simple methods in and out

    sub in { return scalar <STDIN>; } sub out { print @_; }

    You can then use Test::MockObject to mock G::QT:IO during your testing of the "test" method and pass data in/out as you want.

    If you're not so much into mocking objects you could also fork the test and pass the data into your child from the test, or you could put the "test" call into a separate little script and run that via Test::Expect but IMO that's more convoluted. YMMV.

    All dogma is stupid.
      I decided the Test::MockObect route was the easier way to go (I couldn't get Test::Expect and its dependencies to complile on my Windows system, and jcwren's system already had T::MO installed)

      That said, I implemented the Games::QuizTaker:IO module and inserted it into the test section, so that it looks like the following:
      print"Question Number $question_number\n"; foreach $line(@{$$questions{$key}}){ Games::QuizTaker::IO->out(wrap ("","","$line\n")); } print"Your Answer: "; $answer=Games::QuizTaker::IO->in; chomp($answer);
      Well, the in method works fine, the out method has a slight problem. When I run a simple test script inside my development folder, this is what I get for output:
      Question Number 1 Games::QuizTaker::IOWhat popular operating system was created by a Fin +nish computer science student name Linus Torvalds? Games::QuizTaker::IOA. Unix Games::QuizTaker::IOB. Minux Games::QuizTaker::IOC. Linux Games::QuizTaker::IOD. Windows Your Answer:
      Any suggestions?

      I figured it out. I changed the call from Games::QuizTaker::IO->out to Games::QuizTaker::IO::out. That got rid of the module name in front of the answers. Now to get the test working :-)

      People sleep peaceably in their beds at night only because rough men stand ready to do violence on their behalf. -- George Orwell