Shell Test Tools

An AperiTestCase decorator. Test shell scripts, including interactive scripts. Read from sdout/stderr and write to stdin.

Injected Methods

In Use

A test might look something like this. First, the script to test, greet.php:

<?php    

fwrite
("hello world! hello! hello!\n");
exit(
0);

Decorate the standard test case with ShellTestTools:

<?php    

class YourTestCase extends AperiUnitTest {

    function 
beforeInvoking() {
        
$this->mixin('ShellTestTools');
    }

Test the script:

<?php    

class YourTestCase extends AperiUnitTest {

    function 
beforeInvoking() {
        ...
    }
    function 
test() {
        
$this->runScript('php greet.php');
        
$this->assertStdoutHas('/hello world/i');
    }

Often it's better to assert a few, significant parts of the output rather than an identical string comparison of the entire text.

The ~Has() methods accept a variable number of aguments. You can optionally specify the number of matches:

<?php    

class YourTestCase extends AperiUnitTest {
    ...
    ...
    function 
test() {
        
$this->runScript('php greet.php');
        
$this->assertStdoutHas(3"/hello/");
    }

Testing Interactive Scripts

Use $this->enter($input) for script inputs. This has the same effect as typing in the terminal and hitting enter.

For convenience, the $input arg doesn't have to end in a newline. This will be added automatically if it doesn't exist.

Suppose you want to test the script, petshop.php:

<?php    

    fwrite
(STDOUT"what's your pet?\n");
    
$reply trim(fgets(STDIN));
    if(
'exit' == $reply) {  
        exit(
0);
    }
    if(
'Norwegian Blue' == $reply) {  
        
fwrite(STDERR"he doesn't look at all well\n");
        exit(
1);
    } else {
        
fwrite(STDOUT"that's a nice $reply\n");
        exit(
0);            
    }
<?php    

class YourTestCase extends AperiUnitTest {

    function 
beforeInvoking() {
        
$this->mixin('ShellTestTools');
    }
    function 
test() {
        
$this->runScript('php petshop.php');
        
$this->assertStdoutHas("/what's your pet\?/i");

        
$this->enter('gannet');
        
$this->assertStdoutHas("/that's a nice gannet/i");
    }

To check the stderr output you'd do a similar test with "Norwegian Blue" as the input.

Note that, in an interactive script, assertStdout() does not match against the full stdout output, just the chunks read between prompts. As soon as you enter($input), buffers are filled with the next stdout chunk. The methods: assertStdout, assertStdoutHas, assertStderr, and assertStderrHas all work in this way. Only assertConversationHas looks at the full "conversation" ie the combined stdin, stderr and stdout text in the sequence in which they were read by the wrapper class (note that this may differ slightly from the order in which the writes were made by the wrapped script).

Thus, you can test all the logic pathways in a complex script which contains a series of prompts and inputs. Enter an input, assert the script's stdout/stderr reponse to the input, and repeat until done.

If an interactive test is failing, but you're not sure why, try calling $this->dumpConversation() to see the big picture.

SourceForge.net Logo