This is a tricky problem, but it has various solutions.

One solution is to use IPC::Open3, and to test your script by writing to STDIN programatically, and reading from STDOUT. It would be a lot more convenient to just use a module like Capture::Tiny, but that module doesn't really help you solve the writing to STDIN problem very well. IPC::Run may be easier to use for this.

Another solution is to convert your prompting and input code to use ExtUtils::MakeMaker's prompt function. This function allows you to provide a default value, but also allows you to set the environment variable PERL_MM_USE_DEFAULT to tell prompt to use that default value in lieu of reading from STDIN. It's sort of an odd state of evolution that ExtUtils::MakeMaker contains a prompt function, but ExtUtils::MakeMaker is a core Perl module, as baked into the Perl distribution as strict.

Though it introduces a dependency to do so, IO::Prompt::Tiny puts the function into a module that is less of a kitchen sink, and more appropriately named for what it provides. It still offers compatibility with the PERL_MM_USE_DEFAULT environment variable. Here is an example script using it:

#!/usr/bin/env perl use strict; use warnings; use IO::Prompt::Tiny qw(prompt); my $input = prompt('Enter: ', 50); print "$input\n";

And here is a sample test:

use Test::More; use Capture::Tiny qw(capture); my ($stdout, $stderr, $exit) = capture { local $ENV{'PERL_MM_USE_DEFAULT'} = 1; system('/usr/bin/env', 'perl', './mytest.pl'); }; ok 0 == $exit, 'Clean exit code.'; like $stderr, qr/^\QIs interactive? No/, 'Detected non-interactive mod +e.'; is $stdout, "Enter: [50] 50\n50\n", 'Correct output.';

But this still exposes a weakness in going about testing by looking at STDOUT; you're testing at the highest level, and are unable to examine what's going on at lower levels. It's difficult to unit test. If you went the route of using a modulino you could reconfigure your script for better testability. Modulinos are described in the OReilly book, "Mastering Perl", and also in various online resources, one of the earliest of which is http://www.drdobbs.com/scripts-as-modules/184416165.

By converting to a modulino, breaking functionality into sensible subroutines, and then creating appropriate wrappers around the IO boundaries you can develop tests that validate both the top level code through the use of IO capturing techniques demonstrated above, and also at the unit level. For the unit level tests many of them could mock an output subroutine to avoid hitting STDOUT at all, similar to how prompt allows for hinting STDIN.


Dave


In reply to Re: Outputting input prompt with prove by davido
in thread Outputting input prompt with prove by nysus

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.