Jess Telford
Jess Telford

Reputation: 13200

How to output in CLI during execution of PHP Unit tests?

When running a PHPUnit test, I would like to be able to dump output so I can debug one or two things.

I have tried the following (similar to the PHPUnit Manual example);

class theTest extends PHPUnit_Framework_TestCase
{
    /**
     * @outputBuffering disabled
     */
    public function testOutput() {
        print_r("Hello World");
        print "Ping";
        echo "Pong";
        $out = "Foo";
        var_dump($out);
    }   
}

With the following result:

PHPUnit @package_version@ by Sebastian Bergmann.

.

Time: 0 seconds, Memory: 3.00Mb

OK (1 test, 0 assertions)

Notice there is none of the expected output.

I'm using the HEAD versions of the git repos as of September 19th, 2011.

Output of php -version:

$ php -version
PHP 5.2.9 (cli) (built: Dec  8 2010 11:36:37) 
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2009 Zend Technologies
    with Xdebug v2.1.0, Copyright (c) 2002-2010, by Derick Rethans

Is there anything I'm doing wrong, or is this potentially a PHPUnit bug?

Upvotes: 233

Views: 207608

Answers (21)

jerclarke
jerclarke

Reputation: 1479

Just call ob_flush() after outputting text

Example code:

    public function testDebugOutputToCli() {
        var_dump(new DateTime());
        ob_flush();
    }

Screenshot of code and output:

Screenshot of using ob_flush to echo out content that would otherwise have been hidden by PHPUnit

Why? PHPUnit is always output buffering, so we need to dump the buffer when debugging

I was struggling with all the answers above, especially because the selected answer –using codecept_debug() with --debug as the manual says– caused a huge wave of debug output that made it impossible to use for me.

I was reading the PHPUnit manual like a good nerd and stumbled onto this, which I think explains what causes this whole issue across all of PHPUnit, not just Codeception:

PHPUnit manual, Testing Output: “Sometimes you want to assert that the execution of a method, for instance, generates an expected output (via echo or print, for example). The PHPUnit\Framework\TestCase class uses PHP’s Output Buffering feature to provide the functionality that is necessary for this.”

This makes total sense and explains why we don't see the output. PHPUnit is saving it up in case we want to examine the comments! This is how it should always work in our actual tests, we of course don't want random stuff getting to the screen just because we called a function that uses echo.

But when we're debugging, we just want to see the text right away, and understanding all this, the solution is clear: Just use ob_flush() to print the contents of the output buffer on demand!

Three cheers for reading the fun manuals!

P.S. Also found this tip hidden in How to show var_dumps in phpunit or codeception by Julian on dev.to

Upvotes: 22

iteratorX
iteratorX

Reputation: 9

it's a paid product, but I find it does the job well: Ray from Spatie https://spatie.be/products/ray

just use it like this:

ray('message')

and the message will show up in Ray output window

Upvotes: 0

gpupo
gpupo

Reputation: 982

It is possible to use Symfony\Component\Console\Output\TrimmedBufferOutput and then test the buffered output string like this:

use Symfony\Component\Console\Output\TrimmedBufferOutput;

//...
public function testSomething()
{
   $output = new TrimmedBufferOutput(999);
   $output->writeln('Do something in your code with the output class...');
   
   //test the output:
   $this->assertStringContainsString('expected string...', $output->fetch());   
}

Upvotes: 1

Mohsen Shamohamadi
Mohsen Shamohamadi

Reputation: 67

You can use PHPunit default way of showing messages to debug your variables inside your test like this:

$this->assertTrue(false,$your_variable);

Upvotes: -1

commonpike
commonpike

Reputation: 11185

In short, phpunit supresses STDOUT. It writes to STDERR by default, unless you add --verbose or --debug . You can do one of those things:

  • print your debug output to STDERR instead
  • var_dump your debug as usual but add --verbose to the phpunit command line
  • var_dump your debug as usual but add a line ob_flush(); beneath it
  • use the correct commands in phpunit for testing exactly what you're trying to test here

Obviously, the last thing is the Good Thing to do, and the rest are quick temporary hacks.

Upvotes: 1

leo
leo

Reputation: 1275

If you use Laravel, then you can use logging functions such as info() to log to the Laravel log file under storage/logs. So it won't appear in your terminal but in the log file.

Upvotes: -1

Slawa
Slawa

Reputation: 1217

PHPUnit is hiding the output with ob_start(). We can disable it temporarily.

    public function log($something = null)
    {
        ob_end_clean();
        var_dump($something);
        ob_start();
    }

Upvotes: 6

Fabricio
Fabricio

Reputation: 3297

Just use the --verbose flag when execute phpunit.

$ phpunit --verbose -c phpunit.xml 

The advantage of this method is that you don't need to change the test code, you can print strings, var_dump's o anything you wish always and it will be shown in the console only when verbose mode is set.

I hope this helps.

Upvotes: 7

Matthias Rella
Matthias Rella

Reputation: 31

Hackish, but works: Throw an exception with the debug output as its message.

class theTest extends PHPUnit_Framework_TestCase
{
    public function testOutput() {
        throw new \Exception("hello");
    }   
}

Yields:

...
There was 1 error:

1) theTest::testOutput
Exception: hello

Upvotes: 3

kenorb
kenorb

Reputation: 166359

Here are few methods useful for printing debug messages in PHPUnit 4.x:

  • syslog(LOG_DEBUG, "Debug: Message 1!");

    More practical example:

    syslog(LOG_DEBUG, sprintf("%s: Value: %s", __METHOD__, var_export($_GET, TRUE)));
    

    Calling syslog() will generate a system log message (see: man syslog.conf).

    Note: Possible levels: LOG_DEBUG, LOG_INFO, LOG_NOTICE, LOG_WARNING, LOG_ERR, etc.

    On macOS, to stream the syslog messages in realtime, run:

    log stream --level debug --predicate 'processImagePath contains "php"'
    
  • fwrite(STDERR, "LOG: Message 2!\n");

    Note: The STDERR constant is not available if reading the PHP script from stdin. Here is the workaround.

    Note: Instead of STDERR, you can also specify a filename.

  • file_put_contents('php://stderr', "LOG: Message 3!\n", FILE_APPEND);

    Note: Use this method, if you don't have STDERR constant defined.

  • register_shutdown_function('file_put_contents', 'php://stderr', "LOG: Message 4!\n", FILE_APPEND);

    Note: Use this method, if you'd like to print something at the very end without affecting the tests.

To dump the variable, use var_export(), e.g. "Value: " . var_export($some_var, TRUE) . "\n".

To print above messages only during verbose or debug mode, see: Is there a way to tell if --debug or --verbose was passed to PHPUnit in a test?


Although if testing the output is part of the test it-self, check out: Testing Output docs page.

Upvotes: 0

Chris
Chris

Reputation: 2446

This was taken from PHPUnit Docs about Fixtures.

This should allow you to dump information at any point durring the phpunit test life cycle.

Just replace __METHOD__ in the code below with whatever you want to output

Example 4.2: Example showing all template methods available

<?php
class TemplateMethodsTest extends PHPUnit_Framework_TestCase
{
    public static function setUpBeforeClass()
    {
        fwrite(STDOUT, __METHOD__ . "\n");
    }

    protected function setUp()
    {
        fwrite(STDOUT, __METHOD__ . "\n");
    }

    protected function assertPreConditions()
    {
        fwrite(STDOUT, __METHOD__ . "\n");
    }

    public function testOne()
    {
        fwrite(STDOUT, __METHOD__ . "\n");
        $this->assertTrue(TRUE);
    }

    public function testTwo()
    {
        fwrite(STDOUT, __METHOD__ . "\n");
        $this->assertTrue(FALSE);
    }

    protected function assertPostConditions()
    {
        fwrite(STDOUT, __METHOD__ . "\n");
    }

    protected function tearDown()
    {
        fwrite(STDOUT, __METHOD__ . "\n");
    }

    public static function tearDownAfterClass()
    {
        fwrite(STDOUT, __METHOD__ . "\n");
    }

    protected function onNotSuccessfulTest(Exception $e)
    {
        fwrite(STDOUT, __METHOD__ . "\n");
        throw $e;
    }
}
?>

Upvotes: 4

user895378
user895378

Reputation:

UPDATE

Just realized another way to do this that works much better than the --verbose command line option:

class TestSomething extends PHPUnit_Framework_TestCase {
    function testSomething() {
        $myDebugVar = array(1, 2, 3);
        fwrite(STDERR, print_r($myDebugVar, TRUE));
    }
}

This lets you dump anything to your console at any time without all the unwanted output that comes along with the --verbose CLI option.


As other answers have noted, it's best to test output using the built-in methods like:

$this->expectOutputString('foo');

However, sometimes it's helpful to be naughty and see one-off/temporary debugging output from within your test cases. There is no need for the var_dump hack/workaround, though. This can easily be accomplished by setting the --verbose command line option when running your test suite. For example:

$ phpunit --verbose -c phpunit.xml

This will display output from inside your test methods when running in the CLI environment.

See: Writing Tests for PHPUnit - Testing Output.

Upvotes: 272

jasonbar
jasonbar

Reputation: 13461

It's not a bug, but very much intentional. Your best bet is to write to a log file of some kind and tail the log to watch for output.

If you are trying to TEST output, check this out.

Also:

Note: Please note that PHPUnit swallows all output that is emitted during the execution of a test. In strict mode, a test that emits output will fail.

Upvotes: 10

Sudo
Sudo

Reputation: 107

I output my Testresults HTML based, in this case it was helpfull to flush the content:

var_dump($array);
ob_flush();

There is a second PHP Method

flush() 

which i not has tried.

Upvotes: 1

chim
chim

Reputation: 8573

Try using --debug

Useful if you're trying to get the right path to an include or source data file.

Upvotes: 45

Branny Bk
Branny Bk

Reputation: 41

In laravel 5 you can use dump(), Dump the content from the last response.

class ExampleTest extends TestCase{
    public function test1()
    {
        $this->post('/user', ['name' => 'Gema']);
        $this->dump();
    }
}

gives

Upvotes: 4

mkungla
mkungla

Reputation: 3538

For some cases one could use something like that to output something to the console

class yourTests extends PHPUnit_Framework_TestCase
{
    /* Add Warnings */
    protected function addWarning($msg, Exception $previous = null)
    {
        $add_warning = $this->getTestResultObject();
        $msg = new PHPUnit_Framework_Warning($msg, 0, $previous);
        $add_warning->addWarning($this, $msg, time());
        $this->setTestResultObject($add_warning);
    }

    /* Add errors */
    protected function addError($msg, Exception $previous = null)
    {
        $add_error = $this->getTestResultObject();
        $msg = new PHPUnit_Framework_AssertionFailedError($msg, 0, $previous);
        $add_error->addError($this, $msg, time());
        $this->setTestResultObject($add_error);
    }

    /* Add failures */
    protected function addFailure($msg, Exception $previous = null)
    {
        $add_failure = $this->getTestResultObject();
        $msg = new PHPUnit_Framework_AssertionFailedError($msg, 0, $previous);
        $add_failure->addFailure($this, $msg, time());
        $this->setTestResultObject($add_failure);
    }

    public function test_messages()
    {
        $this->addWarning("Your warning message!");
        $this->addError("Your error message!");
        $this->addFailure("Your Failure message");
    }

    /* Or just mark test states! */
    public function test_testMarking()
    {
        $this->markTestIncomplete();
        $this->markTestSkipped();
    }
}

Upvotes: 4

Jess Telford
Jess Telford

Reputation: 13200

Update: See rdlowrey's update below regarding the use of fwrite(STDERR, print_r($myDebugVar, TRUE)); as a much simpler work around


This behaviour is intentional (as jasonbar has pointed out). The conflicting state of the manual has been reported to PHPUnit.

A work-around is to have PHPUnit assert the expected output is empty (when infact there is output) which will trigger the unexpected output to be shown.

class theTest extends PHPUnit_Framework_TestCase
{
    /**
     * @outputBuffering disabled
     */
    public function testOutput() {
        $this->expectOutputString(''); // tell PHPUnit to expect '' as output
        print_r("Hello World");
        print "Ping";
        echo "Pong";
        $out = "Foo";
        var_dump($out);
    }   
}

gives:

PHPUnit @package_version@ by Sebastian Bergmann.

F

Time: 1 second, Memory: 3.50Mb

There was 1 failure:

1) theTest::testOutput
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-''
+'Hello WorldPingPongstring(4) "Foo"
+'

FAILURES!
Tests: 1, Assertions: 1, Failures: 1.

Be certain to disable any other assertions you have for the test as they may fail before the output assertion is tested (and hence you wont see the output).

Upvotes: 38

Gadelkareem
Gadelkareem

Reputation: 1087

I had to modify source code for this code to work so you need to add URL for this forked repos to composer for this will work

class TestCase extends \PHPUnit_Framework_TestCase
{
    /**
     *  Save last response
     * @var Response|null A Response instance
     */
    static $lastResponse;
    /**
     *  Modify to save response
     *
     * @param  string $method
     * @param  string $uri
     * @param  array $parameters
     * @param  array $files
     * @param  array $server
     * @param  string $content
     * @param  bool $changeHistory
     * @return \Illuminate\Http\Response
     */
    final public function call(
        $method,
        $uri,
        $parameters = [],
        $files = [],
        $server = [],
        $content = null,
        $changeHistory = true
    ) {

        $response = parent::call($method, $uri, $parameters, $files, $server, $content, $changeHistory);
        static::$lastResponse = $this->client->getResponse();
        return $response;
    }


    /**
     * Modify message to add response text
     *
     * @param mixed $value
     * @param PHPUnit_Framework_Constraint $constraint
     * @param string $message
     * @since  Method available since Release 3.0.0
     */
    final public static function assertThat($value, PHPUnit_Framework_Constraint $constraint, $message = '')
    {
        $message .= PHP_EOL . static::$lastResponse . PHP_EOL;
        parent::assertThat($value, $constraint, $message);
    }
}

Upvotes: 0

Bob Stein
Bob Stein

Reputation: 17204

I'm having some luck with VisualPHPUnit, and it does helpfully show output, among other things.

class TestHello extends PHPUnit_Framework_TestCase 
{
    public function test_Hello() 
    {
        print "hello world";
    }
}

TestHello results

Upvotes: 7

cweiske
cweiske

Reputation: 31078

You should really think about your intentions: If you need the information now when debugging to fix the test, you will need it next week again when the tests break.

This means that you will need the information always when the test fails - and adding a var_dump to find the cause is just too much work. Rather put the data into your assertions.

If your code is too complex for that, split it up until you reach a level where one assertion (with a custom message) tells you enough to know where it broke, why and how to fix the code.

Upvotes: 7

Related Questions