【问题标题】:Laravel 5.4 testing with Mail::fake - how to access message body?Laravel 5.4 使用 Mail::fake 进行测试 - 如何访问邮件正文?
【发布时间】:2021-12-09 16:51:50
【问题描述】:

我正在运行 Laravel 5.4 并使用 Mail::fake() 和 Mail::assertSent() 测试 Mailables。有诸如 hasTo($email) 和 hasCc($email) 之类的断言,但似乎没有办法访问消息内容。我想测试电子邮件正文是否包含特定字符串。

伪代码:

Mail::assertSent(UserInvited::class, function($mail) use($token) {
    return $mail->bodyContains($token); # that method does not really exist
});

这可能吗?

【问题讨论】:

  • 你找到解决办法了吗?

标签: php laravel-5


【解决方案1】:

遇到同样的情况并且没有任何搜索结果 - 调试后:

Mail::assertSent(InstanceOfMailableEmail::class, function($mail) use ($needle) {

    // now your email has properties set
    $mail->build(); 

    //check the content body for a string
    return strpos($mail->viewData['content'], $needle) !== false;
});

【讨论】:

  • 内容是可邮寄类的属性吗?
  • viewData 是,是一个数组; content 是该数组上的键之一; buildViewData 中发生了一些神奇的事情,这表明 content 应该是 Mailable 的属性(因为它从反映这一点来填充 viewData),但我不记得为什么我不能使用它。也许它是受保护的,我不记得了(那是前一段时间;))
  • 我使用的是 Laravel 5.6,在调用 build 后,$mail->viewData 似乎为空
  • 这是一个非常糟糕的解决方案,因为您正在断言源/原始变量,而不是呈现的电子邮件。也许您呈现的电子邮件不会有任何这些
  • @DenisMysenko 很乐意使用$mail->getContent()(如果存在),而无需此解决方法。如果您有想法如何完成这样的断言,请发布!
【解决方案2】:

有一个包可以用来测试邮件。但就目前而言,你必须要有一点创意才能让它工作,因为他们没有在 reqs 中指定 Laravel 5.4.*。因此,请进入您的 composer.json 文件并从此 repo 构建您自己的包,并使用 Laravel 5.4.* 的更新要求,如下所示:

"repositories": [
    {
        "type": "package",
        "package": {
            "name": "spinen/laravel-mail-assertions",
            "version": "0.1.2",
            "require": {
                "php": ">=5.5.0",
                "illuminate/support": "~5.1.10|5.2.*|5.3.*|5.4.*",
                "swiftmailer/swiftmailer": "~5.1"
            },
            "require-dev": {
                "mockery/mockery": "^0.9.1",
                "phpunit/phpunit": "~4.0|~5.0",
                "psy/psysh": "^0.5.1",
                "satooshi/php-coveralls": "^0.6.1",
                "symfony/var-dumper": "~2.7|~3.0"
            },
            "autoload": {
                "psr-4": {
                    "Spinen\\MailAssertions\\": "src"
                }
            },
            "autoload-dev": {
                "psr-4": {
                    "Spinen\\MailAssertions\\": "tests"
                }
            },
            "config": {
                "preferred-install": "dist"
            },
            "dist": {
                "url": "https://github.com/spinen/laravel-mail-assertions/archive/0.1.1.zip",
                "type": "zip"
            }
        }
    }
],

然后,在require-dev 下,添加您的自定义包:

"require-dev": {
    "spinen/laravel-mail-assertions": "^0.1.2"
},

安装后,在您的 .env 文件中设置 MAIL_DRIVER=log 并将 Spinen\MailAssertions\MailTracking 特征拉入您的测试。此 trait 具有诸如 seeEmailContainsseeEmailSubjectContains 等方法来断言已发送的任何电子邮件中都存在文本。

【讨论】:

    【解决方案3】:

    这是我的做法(以及关于如何做其他事情的有用提示):

    Mail::fake(); //https://laravel.com/docs/5.7/mocking#mail-fake
    $firstName = 'Sally';    
    $self = $this;
    Mail::assertQueued(MyMailable::class, function($mail) use($self, $firstName) {
        $mail->build(); // to set the email properties            
        $self->assertEquals($firstName, $mail->viewData["firstName"]);
        $self->assertEquals(["X-SES-CONFIGURATION-SET" => config('services.ses.options.ConfigurationSetName')], $mail->getHeaders());
        $self->assertTrue($mail->hasBcc(config('mail.supportTeam.address'), config('mail.supportTeam.name')));
        return true;
    });
    

    【讨论】:

    • 在 Laravel 5.6 中 $mail->viewData 为空。它只能从 5.7 开始工作吗?而viewData 仅用于访问可邮寄的属性,对吗?获取mailable的渲染内容没有帮助吗?
    • @Adam 我对 5.6 不熟悉,因为这是一年多以前的事了,我也不确定 5.7+ 的细节。我看到其他答案也提到了$mail->viewData
    【解决方案4】:

    GitHub 上有一个问题要求这样做:https://github.com/laravel/ideas/issues/405

    Taylor 似乎没有发表评论就关闭了这个请求。

    如果你想检查一个字符串是否在呈现的邮件中,你可以不模拟 Mail 门面。只需这样做:

    $mail  = new Mailable(...);
    $html  = $mail->render();
    $found = (strpos($html, 'Hello') !== false);
    

    【讨论】:

      【解决方案5】:

      在创建假邮件之前保留原始邮件管理器的技巧可以解决问题。一旦你准备好运行Mailable的断言,恢复原来的MM。

      例子:

          public function testInvite(): void
          {
              $mailerOriginal = Mail::getFacadeRoot();
              static::assertTrue(\assert($mailerOriginal instanceof MailManager));
              Mail::fake();
      
              // --- Your test logic. --- 
      
              // Note that the callback will be called as many times as there
              // were emails sent (of the given type).
              Mail::assertSent(DocumentShareAccess::class, function (DocumentShareAccess $mail) use ($mailerOriginal): bool {
                  // The fake has no rendering capability, so have to swap back.
                  Mail::swap($mailerOriginal);
      
                  $mail->assertSeeInHtml('contact the document owner');
                  static::assertTrue($mail->hasTo($invitee->email), $invitee->email);
      
                  return true;
              });
          }
      

      【讨论】:

        猜你喜欢
        • 2017-12-14
        • 2019-01-13
        • 2018-09-11
        • 2015-09-16
        • 1970-01-01
        • 2012-02-11
        • 2017-12-05
        • 2020-05-24
        • 1970-01-01
        相关资源
        最近更新 更多