я использую Symfony\Component\Console\Output\ConsoleOutput
написать в консоль.
Я прямо пишу php://stdout
,
В моих модульных тестах я хотел бы иметь возможность проверить вывод на консоль.
Использование метода PHPUnit expectOutputString()
Я могу проверить вывод:
// Passes, as expected
public function testOutputBufferingEcho()
{
$this->expectOutputString('Hello');
echo 'Hello';
}
Это работает с выводом на php://output
тоже:
// Passes, as expected
public function testOutputBufferingOutput()
{
$this->expectOutputString('Hello');
$out = fopen('php://output', 'w');
fputs ($out, 'Hello');
fclose($out);
}
Тем не менее, он не работает с выводом на php://stdout
(тот самый ConsoleOutput
используется по умолчанию):
// Failed asserting that two strings are equal.
// --- Expected
// +++ Actual
// @@ @@
// -'Hello'
// +''
public function testOutputBufferingStdOut()
{
$this->expectOutputString('Hello');
$out = fopen('php://stdout', 'w');
fputs ($out, 'Hello');
fclose($out);
}
Кроме того, кажется, что невозможно использовать ob_*
функции для захвата вывода непосредственно в php://stdout
,
Есть ли способ проверить вывод php://stdout
с PHPUnit?
Или есть какой-либо другой способ записать вывод в php://stdout
в строку (и так проверить в PHPUnit)?
Вышеуказанные тесты выполнялись в PHPUnit 5.5.5.
Заранее спасибо.
Быстрый и грязный способ захвата php://stdout
(или любой другой поток) будет использовать более быстрый и грязный фильтр потока.
class Intercept extends php_user_filter
{
public static $cache = '';
public function filter($in, $out, &$consumed, $closing)
{
while ($bucket = stream_bucket_make_writeable($in)) {
self::$cache .= $bucket->data;
$consumed += $bucket->datalen;
stream_bucket_append($out, $bucket);
}
return PSFS_PASS_ON;
}
}
stream_filter_register("intercept", "Intercept");
$stdout = fopen('php://stdout', 'w'); // or $yerSymfonyThingy->getStream()
stream_filter_append($stdout, "intercept");
fwrite($stdout, "Hello\n");
var_dump(Intercept::$cache);
Hello
string(6) "Hello
"
Все, что записано в поток, собирается в Intercept::$cache
для вашего сведения.
Вы также можете предотвратить нормальный вывод потока, заменив PSFS_PASS_ON
с PSFS_FEED_ME
если хочешь.
Есть способ заменить STDOUT любым другим ресурсом: закройте его. Следующий открытый ресурс будет иметь файловый дескриптор «1» (STDOUT), потому что это первый свободный ресурс.
fclose(STDOUT);
$fakestdout = fopen('php://memory', 'r+');
Теперь любой вывод идет в $fakestdout
и вы можете прочитать из него в вашем тестовом случае.
Единственная проблема заключается в том, что эту операцию нельзя отменить. Таким образом, теперь каждая попытка записи в STDOUT (включая «эхо») будет $fakestdout
или никуда, после того как ты его закроешь. Вы не можете открыть STDOUT после закрытия.
Но если вы запустите PHPUnit с --stderr
аргумент для использования STDERR для вывода PHPUnit, это должно работать.