olidem
olidem

Reputation: 2121

PHPUnit run callback on failed assertion

I am testing a symfony app.

when an assertion fails, I would like to see the web client HTML output. I am seeking for a short and elegant version of this:

if(1 !== $crawler->filter('.flash-success')->count())
    file_put_contents("debug.html", $this->client->getResponse()->getContent());
$this->assertEquals(1, $crawler->filter('.flash-success')->count());

My proposal is to register a callback that gets the 3rd parameter of the assertXXX:

// ideally like this
phpunit_register_callback(write_to_disk_callback);
$this->assertEquals(1, $crawler->filter('.flash-success')->count(), $this->client->getResponse()->getContent());

In my case the callback should write the message to a file on disk, so I can open it with a browser...

function write_to_disk_callback($message){
    file_put_contents("debug.html", $message);
}

Upvotes: 0

Views: 860

Answers (1)

Picoss
Picoss

Reputation: 2057

I think should take a look at the phpunit listeners

Here is a little example of how you implement a listener in your SF project

First you have to create a listener:

<?php

namespace Tests\PHPUnit;

use PHPUnit\Framework\AssertionFailedError;
use PHPUnit\Framework\Test;
use PHPUnit\Framework\TestListener;
use PHPUnit\Framework\TestListenerDefaultImplementation;
use Symfony\Bundle\FrameworkBundle\Client;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

class SimpleTestListener implements TestListener
{
    use TestListenerDefaultImplementation;

    public function addFailure(Test $test, AssertionFailedError $e, float $time): void
    {
        if ($test instanceof WebTestCase && method_exists($test, 'getClient')) {
            /** @var Client $client */
            $client = $test->getClient();

            // Write the client response to a file
        }
    }
}

Then, add the listener on your phpunit.xml:


<listeners>
    ...
    <listener class="Tests\PHPUnit\SimpleTestListener"/>
</listeners>

Finaly, update your test file:

<?php

namespace Tests\PHPUnit\YesWeHack;

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

class MyTest extends WebTestCase
{
    static private $client;

    static public function getClient()
    {
        return static::$client;
    }

    protected static function createClient(array $options = [], array $server = [])
    {
        static::$client = parent::createClient($options, $server);

        return static::$client;
    }

    public function testReportIsFixed()
    {
        $client = static::createClient();

        $client->request('GET', '/');

        $this->assertEquals(500, $client->getResponse()->getStatusCode());
    }
}

Note that the MyTest class is just an example and should not be use like that, It is just for the purpose example. At least you should propably move the statics prop and methods to an abstract class that your tests will extends.

Here is the result of a simple test on a project where I dump the response code and response content in the listener:

PHPUnit 7.5.8 by Sebastian Bergmann and contributors.

Testing Project Test Suite
int(200)
string(523) "<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Home</title>
            </head>
    <body>
        <div class="form">

    <form name="form" method="post">
        <div><label for="form_username" class="required">Username</label><input type="text" id="form_username" name="form[username]" required="required" /></div>
        <input type="hidden" id="form__token" name="form[_token]" value="2AsriLX8VMS0VqomR2wtTGk159TXMhYQJlPt_Chwtv8" />
    </form>
</div>
            </body>
</html>
"
F                                                                   1 / 1 (100%)

Time: 118 ms, Memory: 16.00 MB

There was 1 failure:

1) Tests\PHPUnit\YesWeHack\YWH_PGM5_1Test::testReportIsFixed
Failed asserting that 200 matches expected 500.

MyTest.php:29

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

Upvotes: 3

Related Questions