【问题标题】:How to assert if a phpunit test writes a certain log entry / how to assert if emails are sent如何断言 phpunit 测试是否写入了某个日志条目/如何断言是否发送了电子邮件
【发布时间】:2022-01-17 23:08:13
【问题描述】:

我在 php8 上的 symfony5 项目中有一个服务类,它按照某些规则发送电子邮件。通过我的测试,想检查是否发送了正确的邮件。这个任务存在于几个项目中,所以我真的很想为此找到一个解决方案。

收集邮件接收者的方法目前是私有的,你不应该暴露你的私有。

一个想法是为每个潜在的邮件接收者编写一个日志条目。但是如何检查我的 test.log 文件中的某些值?

我找到了一个包,它扩展了 phpunit 只是为了这个目的 (https://github.com/phoenixrvd/phpunit-assert-log-entry),但它看起来并没有被维护。

你知道两者的解决方案吗

  • 检查日志中的消息 或
  • 有不同的方法来测试是否通知了正确的接收者?

目前我使用 Trait 向我的服务添加日志记录功能,该服务有一个 setter 方法,该方法通过 @required 注释设置 Logger。


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);
        }
    }

【问题讨论】:

    标签: php phpunit symfony5 monolog


    【解决方案1】:

    依赖注入的一大优势 - 传递依赖,而不是按需创建它们 - 是您可以用 test doubles 替换它们 - 存根、模拟和间谍。 PHPUnit supports test doubles out of the box 有你需要的一切。

    要断言记录了特定行,您需要:

    • 创建LoggerInterface 的模拟实现
    • 告诉模拟它应该期待对 info 方法的特定调用
    • 将模拟设置为您要测试的类实例的记录器

    例如:

    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');
    }
    

    断言发送了特定的电子邮件将类似地完成:实际发送电子邮件的类应该是决定发送哪些电子邮件的类的依赖项。所以你可能会有这样的事情:

    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');
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-06
      • 2012-12-20
      • 2018-09-13
      • 2022-08-16
      • 2018-02-11
      相关资源
      最近更新 更多