-
-
Notifications
You must be signed in to change notification settings - Fork 9.7k
[FrameworkBundle] Add LoggerAssertionsTrait
which provide shortcuts to assert a log has been written
#51696
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[FrameworkBundle] Add LoggerAssertionsTrait
which provide shortcuts to assert a log has been written
#51696
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Bundle\FrameworkBundle\Test; | ||
|
||
use Monolog\Handler\TestHandler; | ||
use Monolog\Logger; | ||
use Monolog\LogRecord; | ||
|
||
trait LoggerAssertionsTrait | ||
{ | ||
public static function assertLogExists(string $expectedLog, string $level = Logger::DEBUG): void | ||
{ | ||
self::ensureMonologHandlerIsAvailable(); | ||
|
||
/** @var TestHandler $logger */ | ||
$logger = self::getContainer()->get('monolog.handler.test'); | ||
welcoMattic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
self::assertTrue($logger->hasRecordThatPasses( | ||
function (array|LogRecord $record) use ($expectedLog) { | ||
return $record['message'] === $expectedLog; | ||
}, | ||
$level, | ||
)); | ||
} | ||
|
||
public static function assertLogMatches(string $expectedRegex, string $level = Logger::DEBUG): void | ||
{ | ||
self::ensureMonologHandlerIsAvailable(); | ||
|
||
/** @var TestHandler $logger */ | ||
$logger = self::getContainer()->get('monolog.handler.test'); | ||
|
||
self::assertTrue($logger->hasRecordThatMatches($expectedRegex, $level)); | ||
} | ||
|
||
public static function assertLogContains(string $expectedLog, string $level = Logger::DEBUG): void | ||
{ | ||
self::ensureMonologHandlerIsAvailable(); | ||
|
||
/** @var TestHandler $logger */ | ||
$logger = self::getContainer()->get('monolog.handler.test'); | ||
|
||
self::assertTrue($logger->hasRecordThatContains($expectedLog, $level)); | ||
} | ||
|
||
/** | ||
* @internal | ||
*/ | ||
private static function ensureMonologHandlerIsAvailable(): void | ||
{ | ||
if (!self::getContainer()->has('monolog.handler.test')) { | ||
self::fail('The "monolog.handler.test" service is not available. Try registering the service "Monolog\Handler\TestHandler" as "monolog.handler.test" in your test configuration.'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about mentioning using the Monolog bundle configuration if available? when@test:
monolog:
handlers:
test: { type: test }
main:
type: fingers_crossed
# […] This would work, because it'll be registered through the Monolog bundle extension in the handlers chain, but I don't get how just registering a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are right, I should belongs to the Monolog bridge, as it only works with Monolog. Or I have to reimplement I'm going to move it, thanks for your feedback There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't well know this part, especially how to use this bridge in tests. Would you help me? |
||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller; | ||
|
||
use Psr\Log\LoggerInterface; | ||
use Symfony\Component\HttpFoundation\Response; | ||
|
||
final class LoggerController | ||
{ | ||
public function index(LoggerInterface $logger) | ||
{ | ||
$logger->debug('test1_'.__CLASS__); | ||
$logger->debug('test2_'.__CLASS__); | ||
$logger->debug('test3_'.__CLASS__); | ||
|
||
return new Response(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Logger; | ||
|
||
use Monolog\Logger; | ||
|
||
class TestLogger extends Logger | ||
{ | ||
public array $logs = []; | ||
|
||
public function __construct($handler) | ||
{ | ||
parent::__construct(__CLASS__, [$handler]); | ||
} | ||
|
||
public function log($level, $message, array $context = []): void | ||
{ | ||
$this->logs[] = [ | ||
'level' => $level, | ||
'message' => (string) $message, | ||
'context' => $context, | ||
]; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Logger; | ||
|
||
use Monolog\Logger; | ||
|
||
class TestLoggerWithoutHandler extends Logger | ||
{ | ||
public array $logs = []; | ||
|
||
public function __construct() | ||
{ | ||
parent::__construct(__CLASS__); | ||
} | ||
|
||
public function log($level, $message, array $context = []): void | ||
{ | ||
$this->logs[] = [ | ||
'level' => $level, | ||
'message' => (string) $message, | ||
'context' => $context, | ||
]; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional; | ||
|
||
use PHPUnit\Framework\AssertionFailedError; | ||
|
||
final class LoggerTest extends AbstractWebTestCase | ||
{ | ||
public function testLoggerAssertion() | ||
{ | ||
$client = $this->createClient(['test_case' => 'Logger', 'root_config' => 'config.yml', 'debug' => true]); | ||
$client->request('GET', '/log'); | ||
|
||
$this->assertLogExists('test1_Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\LoggerController'); | ||
$this->assertLogMatches('/(test2_).*(LoggerController)/'); | ||
$this->assertLogContains('test3'); | ||
} | ||
|
||
public function testLoggerAssertionWithoutTestHandler() | ||
{ | ||
$client = $this->createClient(['test_case' => 'LoggerWithoutHandler', 'root_config' => 'config.yml', 'debug' => true]); | ||
$client->request('GET', '/log'); | ||
|
||
try { | ||
$this->assertLogExists('test1_Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\LoggerController'); | ||
} catch (AssertionFailedError $e) { | ||
$this->assertSame('The "monolog.handler.test" service is not available. Try registering the service "Monolog\Handler\TestHandler" as "monolog.handler.test" in your test configuration.', $e->getMessage()); | ||
} | ||
|
||
try { | ||
$this->assertLogMatches('/(test2_).*(LoggerController)/'); | ||
} catch (AssertionFailedError $e) { | ||
$this->assertSame('The "monolog.handler.test" service is not available. Try registering the service "Monolog\Handler\TestHandler" as "monolog.handler.test" in your test configuration.', $e->getMessage()); | ||
} | ||
|
||
try { | ||
$this->assertLogContains('test3'); | ||
} catch (AssertionFailedError $e) { | ||
$this->assertSame('The "monolog.handler.test" service is not available. Try registering the service "Monolog\Handler\TestHandler" as "monolog.handler.test" in your test configuration.', $e->getMessage()); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
use Symfony\Bundle\FrameworkBundle\FrameworkBundle; | ||
use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestBundle; | ||
|
||
return [ | ||
new FrameworkBundle(), | ||
new TestBundle(), | ||
]; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
imports: | ||
- { resource: ../config/default.yml } | ||
- { resource: services.yml } | ||
|
||
framework: | ||
profiler: ~ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
_loggertest_bundle: | ||
resource: '@TestBundle/Resources/config/routing.yml' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
services: | ||
_defaults: | ||
public: true | ||
|
||
Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\LoggerController: | ||
tags: ['controller.service_arguments'] | ||
|
||
monolog.handler.test: | ||
class: Monolog\Handler\TestHandler | ||
|
||
logger: | ||
class: Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Logger\TestLogger | ||
arguments: ['@monolog.handler.test'] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Symfony package. | ||
* | ||
* (c) Fabien Potencier <fabien@symfony.com> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
use Symfony\Bundle\FrameworkBundle\FrameworkBundle; | ||
use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestBundle; | ||
|
||
return [ | ||
new FrameworkBundle(), | ||
new TestBundle(), | ||
]; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
imports: | ||
- { resource: ../config/default.yml } | ||
- { resource: services.yml } | ||
|
||
framework: | ||
profiler: ~ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
_loggertest_bundle: | ||
resource: '@TestBundle/Resources/config/routing.yml' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
services: | ||
_defaults: | ||
public: true | ||
|
||
Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\LoggerController: | ||
tags: ['controller.service_arguments'] | ||
|
||
logger: | ||
class: Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Logger\TestLoggerWithoutHandler |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The signature is wrong. Monolog's level constants on the Logger class are integers, not strings.
And they are deprecated in favor of the enum in 3.x.
and in 3.x, the various
hasRecord*
methods of theTestHandler expect the Level enum.