I am using Symfony\Component\Console\Output\ConsoleOutput
to write to the console.
Explicitly, I am writing to php://stdout
.
In my unit tests, I would like to be able to check the output to the console.
Using the PHPUnit method expectOutputString()
, I can check for output:
// Passes, as expected
public function testOutputBufferingEcho()
{
$this->expectOutputString('Hello');
echo 'Hello';
}
This works with output to php://output
too:
// Passes, as expected
public function testOutputBufferingOutput()
{
$this->expectOutputString('Hello');
$out = fopen('php://output', 'w');
fputs ($out, 'Hello');
fclose($out);
}
However, it does not work with output to php://stdout
(the one ConsoleOutput
uses as default):
// 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);
}
Additionally, it appears it is not possible to use the ob_*
functions to capture output directly to php://stdout
.
Is there anyway to test output to php://stdout
with PHPUnit?
Or is there any other way to capture the output to php://stdout
into a string (and so test in PHPUnit)?
The above tests ran in PHPUnit 5.5.5.
Thank you in advance.
There is a way to replace STDOUT with any other resource: Close it. The next opened resource will have the file descriptor "1" (STDOUT) because this is the first free one.
fclose(STDOUT);
$fakestdout = fopen('php://memory', 'r+');
Now any output goes to $fakestdout
and you can read from it in your test case.
The only problem is that this operation cannot be reverted. So from now on every attempt to write to STDOUT (including "echo") will go to $fakestdout
, or nowhere, after you close it. You cannot reopen STDOUT once closed.
But if you run PHPUnit with the --stderr
argument to use STDERR for the PHPUnit output, this should work.
A quick and dirty way to capture php://stdout
(or any other stream) would be to use a quicker and dirtier stream filter.
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
"
Everything written to the stream gets collected in Intercept::$cache
for your perusal.
You can prevent normal output of the stream as well by replacing PSFS_PASS_ON
with PSFS_FEED_ME
if you like.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With