如何断言 phpunit 测试是否写入某个日志条目/如何断言是否已发送电子邮件
How to assert if a phpunit test writes a certain log entry / how to assert if emails are sent
我在 php8 上的 symfony5 项目中有一项服务 class,它按照特定规则发送电子邮件。通过我的测试,我想检查是否发送了正确的邮件。这个任务存在于几个项目中,所以我真的很想为此找到一个解决方案。
收集邮件收件人的方法目前是私有的,你不应该暴露你的隐私。
一个想法是为每个潜在的邮件接收者写一个日志条目。但是如何检查我的 test.log 文件中的某些值?
我找到了一个包,它扩展了 phpunit 只是为了这个目的(https://github.com/phoenixrvd/phpunit-assert-log-entry),但它看起来不像是维护的。
你知道任何一个的解决方案吗
- 检查日志中的消息
或
- 是否有不同的方法来测试是否通知了正确的接收者?
目前我使用 Trait 向我的服务添加日志记录功能,它有一个 setter 方法,它通过 @required
注释设置记录器。
namespace App\Logger;
use Psr\Log\LoggerInterface;
trait LoggerTrait
{
private $logger;
/**
* @required
*/
public function setLogger(LoggerInterface $logger): void
{
$this->logger = $logger;
}
protected function logInfo(string $message, array $context = [])
{
if (null !== $this->logger) {
$this->logger->info($message, $context);
}
}
依赖注入的一大优势 - 传递依赖,而不是按需创建它们 - 是你可以用 test doubles - 存根、模拟和间谍。 PHPUnit supports test doubles out of the box 应有尽有。
要断言特定行已记录,您需要:
- 创建
LoggerInterface
的模拟实现
- 告诉 mock 它应该期待对
info
方法的特定调用
- 将模拟设置为您要测试的class实例的记录器
例如:
public function testLogListsEmailAddress() {
// Create the mock
$mockLogger = $this->createMock(LoggerInterface::class);
// Expect a call to info, with the e-mail address in the message
$mockLogger->expects('info')
->with($this->stringContains('user@example.com');
// Set up the class to test
$classUnderTest = new MyThingummy;
$classUnderTest->setLogger($mockLogger);
// Run the code which should log the address
$classUnderTest->doSomething('user', 'example.com');
}
断言发送特定电子邮件的方式类似:实际发送电子邮件的 class 应该是决定发送哪些电子邮件的 class 的依赖项发送。所以你可能有这样的东西:
public function testLogSendsEmail() {
$mockEmailSender = $this->createMock(EmailSenderInterface::class);
$mockEmailSender->expects('send')
// first argument to send() must be expected address; others can be anything
->with('user@example.com', $this->anything());
// Perhaps in this case, the dependency is passed to the constructor
$classUnderTest = new MyThingummy($mockEmailSender);
$classUnderTest->doSomething('user', 'example.com');
}
我在 php8 上的 symfony5 项目中有一项服务 class,它按照特定规则发送电子邮件。通过我的测试,我想检查是否发送了正确的邮件。这个任务存在于几个项目中,所以我真的很想为此找到一个解决方案。
收集邮件收件人的方法目前是私有的,你不应该暴露你的隐私。
一个想法是为每个潜在的邮件接收者写一个日志条目。但是如何检查我的 test.log 文件中的某些值?
我找到了一个包,它扩展了 phpunit 只是为了这个目的(https://github.com/phoenixrvd/phpunit-assert-log-entry),但它看起来不像是维护的。
你知道任何一个的解决方案吗
- 检查日志中的消息 或
- 是否有不同的方法来测试是否通知了正确的接收者?
目前我使用 Trait 向我的服务添加日志记录功能,它有一个 setter 方法,它通过 @required
注释设置记录器。
namespace App\Logger;
use Psr\Log\LoggerInterface;
trait LoggerTrait
{
private $logger;
/**
* @required
*/
public function setLogger(LoggerInterface $logger): void
{
$this->logger = $logger;
}
protected function logInfo(string $message, array $context = [])
{
if (null !== $this->logger) {
$this->logger->info($message, $context);
}
}
依赖注入的一大优势 - 传递依赖,而不是按需创建它们 - 是你可以用 test doubles - 存根、模拟和间谍。 PHPUnit supports test doubles out of the box 应有尽有。
要断言特定行已记录,您需要:
- 创建
LoggerInterface
的模拟实现
- 告诉 mock 它应该期待对
info
方法的特定调用 - 将模拟设置为您要测试的class实例的记录器
例如:
public function testLogListsEmailAddress() {
// Create the mock
$mockLogger = $this->createMock(LoggerInterface::class);
// Expect a call to info, with the e-mail address in the message
$mockLogger->expects('info')
->with($this->stringContains('user@example.com');
// Set up the class to test
$classUnderTest = new MyThingummy;
$classUnderTest->setLogger($mockLogger);
// Run the code which should log the address
$classUnderTest->doSomething('user', 'example.com');
}
断言发送特定电子邮件的方式类似:实际发送电子邮件的 class 应该是决定发送哪些电子邮件的 class 的依赖项发送。所以你可能有这样的东西:
public function testLogSendsEmail() {
$mockEmailSender = $this->createMock(EmailSenderInterface::class);
$mockEmailSender->expects('send')
// first argument to send() must be expected address; others can be anything
->with('user@example.com', $this->anything());
// Perhaps in this case, the dependency is passed to the constructor
$classUnderTest = new MyThingummy($mockEmailSender);
$classUnderTest->doSomething('user', 'example.com');
}