如何在 symfony phpunit kernelTestCase 中正确注入 monolog.logger / LoggerInterface 作为模拟
Posted
技术标签:
【中文标题】如何在 symfony phpunit kernelTestCase 中正确注入 monolog.logger / LoggerInterface 作为模拟【英文标题】:How to properly inject monolog.logger / LoggerInterface as mock in a symfony phpunit kernelTestCase 【发布时间】:2021-10-08 17:00:40 【问题描述】:我想在服务MyService
中测试服务调用是否是正确的方法$logger->info()
或$logger->error()
。
为此,我编写了以下测试:
use App\Service\MyService;
use App\Tests\Mock\MyServiceHttpClient;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
class MyServiceTest extends KernelTestCase
public function testMyServiceShouldSucceed()
self::bootKernel();
$router = self::$kernel->getContainer()->get('router');
$logger = $this->createMock(LoggerInterface::class);
$logger->expects($this->never())->method('error');
$logger->expects($this->once())->method('info');
$myService = new MyService($logger, $router);
$myService->someMethodIExpectToSucceed();
我的服务.php:
namespace App\Service\MyService;
class MyService
private LoggerInterface $myserviceLogger;
private UrlGeneratorInterface $router;
public function __construct(LoggerInterface $myserviceLogger, UrlGeneratorInterface $router)
$this->logger = $myserviceLogger;
$this->router = $router;
public function someMethodIExpectToSucceed(): void
try
// … some code, api calls, …
$this->logger->info("all was ok, I want that log");
catch (\Exception $e)
$this->logger->error("something wrong happens");
这很好用,但我的服务有更多的依赖项,而不仅仅是 $logger
和 $router
。所以我尝试找到一种方法,首先将模拟注入内核容器中,如下所示:
self::$kernel->getContainer()->set('myservice.logger', $logger);
$myService = self::$kernel->getContainer()->get(MyService::class)->someMethodIExpectToSucceed();
但这似乎不起作用。我不能使用monolog.logger
代替myservice.logger
,因为该服务是私有的,我认为在services_test.yaml
中重新声明monolog.logger
不是一个好主意。但也许我应该?
你有解决办法吗?
【问题讨论】:
【参考方案1】:是的,如果您想在测试中动态重新定义服务,您应该将其定义为“公共”。这是 services_test.yaml 的主要用途。
【讨论】:
【参考方案2】:我有一个 trait,当我想检查正在记录的内容时,在单元测试中使用它。
有了这个,我可以创建/__construct()
我需要的所有其他模拟或真实服务,并创建我想要测试的内容,包括$this->log
代替任何LoggerInterface
,然后获取日志记录关于它的各种断言。
如果我需要在我自己从容器中获取的服务中定期使用它,我会制作类似于服务的东西(仅在测试环境中可用),并将其连接为默认记录器 - 或用于特定服务- 通过 services_test.yaml 文件(或在 packages/test/ 中),获取TestLog
服务并根据需要对其记录的内容进行检查。
<?php
use Monolog\Handler\TestHandler;
use Monolog\Logger;
/**
* Create a dummy logger that can be inspected.
*
* Use `$this->log` on a LoggerInterface parameter to send logs to.
* Make assertions on the contents of `$this->testLog`.
*
* Examples:
* <code>
* * $this->testLog->reset(); // clear the previously log messages
* * $this->assertCount(1, $this->testLog->getRecords(), 'Only expected 1 log message');
* * $this->assertTrue($this->testLog->hasDebugThatMatches('/from the API/'));
* </code>
*/
trait TestLog
protected Logger $log;
protected TestHandler $testLog;
/**
* @before
*/
public function createTestLog(): void
$this->log = new Logger('test');
$this->testLog = new TestHandler();
$this->log->pushHandler($this->testLog);
// more helper/assertion methods
【讨论】:
以上是关于如何在 symfony phpunit kernelTestCase 中正确注入 monolog.logger / LoggerInterface 作为模拟的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 PHPUnit 测试 Symfony 中的字符引用?
Symfony/PhpUnit - 如何测试服务中是不是抛出异常
如何在 symfony phpunit kernelTestCase 中正确注入 monolog.logger / LoggerInterface 作为模拟