How to assert a line is logged using Monolog inside Symfony
As solution:
Get all handlers from monolog
service and search test handler.
foreach ($this->container->get('monolog')->getHandlers() as $handler) { if ($handler instanceof TestHandler) { $testHandler = $handler; break; }}if (!$testHandler) { throw new \RuntimeException('Oops, not exist "test" handler in monolog.');}$this->assertFalse($testHandler->hasCritical()); // Or another assertions
In your command class, you have to simply set the handler with pushHandler()
:
namespace AppBundle\Command;use Symfony\Bridge\Monolog\Handler\ConsoleHandler;use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;use Symfony\Component\Console\Input\InputInterface;use Symfony\Component\Console\Output\OutputInterface;class YourCommand extends ContainerAwareCommand{ // ... protected function execute(InputInterface $input, OutputInterface $output) { $logger = $this->getContainer()->get('logger'); // PUSH THE OutputInterface OBJECT INTO MONOLOG $logger->pushHandler(new ConsoleHandler($output)); // Your command logic here... }
In your test, using CommandTester
:
namespace AppBundle\Tests\Command;use AppBundle\Command\YourCommand;use Symfony\Bundle\FrameworkBundle\Console\Application;use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;use Symfony\Component\Console\Output\OutputInterface;use Symfony\Component\Console\Tester\CommandTester;class YourCommandTest extends KernelTestCase{ public function testExecute() { $kernel = $this->createKernel(); $kernel->boot(); // mock the Kernel or create one depending on your needs $application = new Application($kernel); $application->add(new YourCommand()); $command = $application->find('acme:your:command'); $commandTester = new CommandTester($command); $commandTester->execute( array('command' => $command->getName()), /** * Here set the verbosity */ array('verbosity' => OutputInterface::VERBOSITY_DEBUG) ); // die(print_r($commandTester->getDisplay())); $this->assertRegExp('/.../', $commandTester->getDisplay()); }}
Keep attention to array('verbosity' => OutputInterface::VERBOSITY_DEBUG)
.
This way you'll can obtain all the logs (a INFO in this case, set with $logger->info('Starting <info>acme:your:command</info>');
):
[2015-08-13 23:39:22] app.INFO: Starting acme:your:command:
Now you can use $this->assertRegExp()
to check if a particular line is logged or not.
You can also transform the string
in an array
with
explode('\n', $commandTester->getDisplay())
This solution were found here and is explained in the documentation of Monolog here.
More about Monolog and Symfony (Symfony Docu).
More about Monolog Handlers (Monolog Docu).
Symfony 5 (autowiring), PHP 7.4
namespace App\Command;use Monolog\Logger;use Psr\Log\LoggerInterface;use Symfony\Bridge\Monolog\Handler\ConsoleHandler;use Symfony\Component\Console\Command\Command;use Symfony\Component\Console\Input\InputInterface;use Symfony\Component\Console\Output\OutputInterface;class YourCommand extends Command{ protected static $defaultName = 'acme:your:command'; private LoggerInterface $logger; public function __construct(LoggerInterface $logger) { $this->logger = $logger; } protected function execute(InputInterface $input, OutputInterface $output) { // PUSH THE OutputInterface OBJECT INTO MONOLOG if ($this->logger instanceof Logger) { $this->logger->pushHandler(new ConsoleHandler($output)); } // Your command logic here... return self::SUCCESS; }}
In your test, using CommandTester
:
namespace AppBundle\Tests\Command;use AppBundle\Command\YourCommand;use Symfony\Bundle\FrameworkBundle\Console\Application;use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;use Symfony\Component\Console\Output\OutputInterface;use Symfony\Component\Console\Tester\CommandTester;class YourCommandTest extends KernelTestCase{ public function testExecute() { $kernel = static::createKernel(); $application = new Application($kernel); $command = $application->find('acme:your:command'); $commandTester = new CommandTester($command); $commandTester->execute( ['command' => $command->getName()], /** * Here set the verbosity */ ['verbosity' => OutputInterface::VERBOSITY_DEBUG] ); $output = $commandTester->getDisplay(); // die(print_r($commandTester->getDisplay())); self::assertStringContainsString('/.../', $$output); }}