Как писать модульные тесты для интерактивного консольного приложения
у меня есть консольное приложение (написано как команда Symfony2), которое считывает ввод от пользователя через STDIN
и с помощью readline
, ввод пользователя затем передается в eval()
все это просто для того, чтобы иметь "debug shell" (что-то вроде php -a
), но в рамках проекта env и доступа к контейнеру инъекций зависимостей.
Я хотел бы написать модульные тесты для этой команды, но я ударяю по стене, о том, как (и возможно ли) написать тесты PHPUnit для этого поведение?
1 ответов
Я не знаком с командой Sf2, но в документах 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);
идея состоит в том, чтобы сделать ваш компонент тестируемым, не требуя реальной консоли окружающая среда. Использование этого подхода позволяет проверить содержимое потока в любое время в тесте. поэтому, если вы запустите команду " foo "в своем консольном приложении и хотите проверить, что вывод" bar", вы просто перемотаете соответствующий ресурс и прочитаете его содержимое. Альтернативой было бы использовать SplTempFileObject
.
class ConsoleApp
…
public function __construct($inputStream, $outputStream)
{
$this->inputStream = $inputStream;
$this->outputStream = $outputStream;
}
}
в вашем сценарии реального мира вы создадите консольное приложение с
$app = new ConsoleApp(STDIN, STDOUT);
но в вашем тесте вы можете установить ConsoleApp
потоком на ваш выбор:
public function setup()
{
$i = fopen('php://memory', 'w');
$o = fopen('php://memory', 'w');
$this->consoleApp = new ConsoleApp($i, $o);
}
примером UnitTest, использующего этот метод для outstream, будет