Pragmatism in the real world

Using Monolog's TestHandler

When I write integration tests with PHPUnit, I find it helpful use Monolog‘s TestHandler to check that the logs I expect are generated.

It’s reasonably common that classes that write to a log take a PSR\Log\LoggerInterface in their constructor and then use that for logging. This usually logs to the error handler for pushing to Sentry or whatnot. This makes testing easy!

For testing we can use the TestHandler which stores the logs it receives and then they can then be inspected.

We set up like this:

<?php

namespace Test\Integration;

use Monolog\Handler\TestHandler;
use Monolog\Logger;
use PHPUnit\Framework\TestCase;

class FooTest extends TestCase
{
    protected TestHandler $testHandler;
    protected Logger $logger;

    public function setUp(): void
    {
        $this->testHandler = new TestHandler();
        $this->logger = new Logger('test', [$this->testHandler]);
    }

    // tests here
}

Then we can use it in a test like this:

public function testFoo(): void
{
    $foo = new Foo($this->logger);

    $result = $foo->bar();

    $this->assertTrue($result);

    $this->assertTrue($this->testHandler->hasInfoThatContains('Created Baz'));
}

TestHandler has a number of methods that allow you to determine if a specific log has been written, along with getRecords(), clear(), etc to allow full inspection and control of the test log. Peruse the source for the class to see all the options, noting particularly the set of convenience methods in the DocBlock.

If your system under test uses a PSR-3 logger, then Monolog’s TestHandler is a lovely way to test that your logs are as expected.

Thoughts? Leave a reply

Your email address will not be published. Required fields are marked *