如何为交互式控制台应用程序编写单元测试

can*_*nni 6 php console phpunit stdio

我有一个控制台应用程序,(写成的Symfony2命令)通过读取来自用户的输入STDIN,并与帮助readline,用户输入随后被传递到eval()

整个过程只是用于"调试shell"(类似于a php -a)但在项目环境和依赖注入容器访问中.

我想为这个命令编写单元测试,但是我正在打击墙,关于如何(并且可能)为这种行为编写PHPUnit测试?

Gor*_*don 7

我不熟悉Sf2 Command的事情,但是Sf2文档有一个关于在http://symfony.com/doc/2.0/components/console.html#testing-commands上测试它的例子.

通常,您可以从控制台应用程序中解耦STDIN,STDOUT以便可以将其替换为其他流资源,例如fopen(php://memory).而不是readline,你使用

fwrite($outputStream, 'Prompt');
$line = stream_get_line($inputStream, 1024, PHP_EOL);
Run Code Online (Sandbox Code Playgroud)

我们的想法是在不需要真正的控制台环境的情况下使您的组件可测试.使用此方法可以在测试中随时检查Stream的内容.因此,如果您在控制台应用程序中运行Command"foo"并想要测试输出是"bar",您只需回滚相应的资源并阅读其内容即可.另一种方法是使用SplTempFileObject.

class ConsoleApp
…
    public function __construct($inputStream, $outputStream)
    {
        $this->inputStream = $inputStream;
        $this->outputStream = $outputStream;
    }
}
Run Code Online (Sandbox Code Playgroud)

在您的真实场景中,您将使用创建控制台应用程序

$app = new ConsoleApp(STDIN, STDOUT);
Run Code Online (Sandbox Code Playgroud)

但是在测试中,您可以ConsoleApp使用您选择的流设置:

public function setup()
{
    $i = fopen('php://memory', 'w');
    $o = fopen('php://memory', 'w');
    $this->consoleApp = new ConsoleApp($i, $o);
}
Run Code Online (Sandbox Code Playgroud)

使用此方法进行出口的UnitTest示例如下