【问题标题】:How to test Laravel Mail sent with string body, not using Mailable如何测试使用字符串正文发送的 Laravel 邮件,而不是使用 Mailable
【发布时间】:2020-03-10 08:03:17
【问题描述】:

我有这封电子邮件已发送出去

Mail::send([], [], function ($message) use ($email) {
    $message->to($email->to)
        ->subject($email->subject)
        ->setBody($email->content, 'text/html');
});

如何断言此邮件是在测试中发送的?

使用Mail::fake() 门面,但Mail::assertSent() 想要一个字符串Mailable。

欢迎任何建议。

【问题讨论】:

  • 您可以使用mailtrap.io 而不是创建假的。它来你提供的邮件
  • 您使用 Behat 进行测试吗?如果是,我可能会在这里发布我的测试。我正在使用 Mailtrap API 检查是否可以在 Mailtrap 收件箱中找到电子邮件。
  • 为什么不创建一个Mailable 类?这使得断言非常容易。它让你的开发生活更轻松;)

标签: php laravel testing phpunit laravel-6


【解决方案1】:

默认情况下,PHPUnit 使用array 邮件驱动程序并将所有发送的邮件存储在一个数组中。

所以一种选择是放弃Mail::fake(),在测试中触发电子邮件,然后检查消息数组。

我在测试中使用的自定义断言:

protected function assertMailSentTo($user, $times = 1)
{
    // resolves the mail driver and gets messages
    $messages = app('swift.transport')->messages();

    $filtered = $messages->filter(function ($message) use ($user) {
        return array_key_exists($user->email, $message->getTo());
    });

    $expected = $times;

    $actual = $filtered->count();

    $this->assertTrue(
        $expected === $actual,
        "Sent {$actual} messages instead of {$expected}."
    );
}

【讨论】:

    【解决方案2】:

    Mail::send 返回一个值。 尝试将其分配给变量并检查值;应该为 true(如果邮件已发送)或 false(如果未发送)。 此外,您可以使用像 Mailinator 这样的网站来创建一个临时 ID 来接收邮件。

    【讨论】:

      【解决方案3】:

      几个月前我问过同样的问题,我决定测试是否收到了消息

      也许它违反了“Don't Mock What You Don't Own”规则,但因为它对我有用,所以我决定保留它。

      我不知道您是否像我一样使用Behat,但我希望它可以帮助某人。我也在这里使用MailTrap API。这是物有所值的。

      好吧,一旦你使用 Behat,在你的 FeatureContext.php 创建一个这样的函数:

      /**
       * @Given I received a password reset token link at inbox
       */
      public function iReceivedAPasswordResetTokenLinkAtInbox()
      {
          $inbox = env('MAILTRAP_INBOX');
          $mailTrapToken = env('MAILTRAP_TOKEN');
      
          $options = [
              'headers' => [
                  'Api-Token' => $mailTrapToken              
              ]            
          ];
      
          $client = new GuzzleHttp\Client($options);
          $apiMailTrap = 'https://mailtrap.io/api/v1';
      
          $response = $client->request('GET', "{$apiMailTrap}/inboxes/{$inbox}/messages");
      
          $msg = json_decode($response->getBody()->getContents());
      
          $response = $client->request('GET', "{$apiMailTrap}/inboxes/{$inbox}/".
              "messages/{$msg[0]->id}/body.txt");
      
          // Here you can get the message body and make any verification you need
          $bodyTxt = $response->getBody()->getContents();
      
          // In my case, I had to check if a URL was successfully sent, so        
          $this->tokenPasswordReset = trim(substr($bodyTxt, strpos($bodyTxt,'/resetpassword/') + 15, 60));         
      
          print('token: '.$this->tokenPasswordReset);
      
          // Then I made my assertion
          PHPUnit::assertNotEmpty($this->tokenPasswordReset);
      }
      

      在我的例子中,一旦我有了上面的功能,为了测试一个端点,我简单地添加了一个名为 resetpw.feature 的文件,其中包含:

      Feature: Changing Password
      In order to reset an user password
      As an user
      I want to reset my password and update it
      
      @password
      Scenario: Users want to reset their passwords
      Given I send a POST request to "/resetpassword" with parameters:
      | key        | value                    |
      | email      | behat@mytests.dev        |
      Then the response status code should be 200
      
      Given I received a password reset token link at inbox
      # And here comes the previously created function!
      
      When I access a password reset link with this token
      Then the response status code should be 200
      

      然后我运行behat --tags @password 进行测试。

      就是这样。我希望它可以启发某人!

      【讨论】:

        猜你喜欢
        • 2017-06-25
        • 1970-01-01
        • 2020-04-16
        • 2021-04-17
        • 1970-01-01
        • 1970-01-01
        • 2023-03-13
        • 2013-07-31
        • 2018-06-29
        相关资源
        最近更新 更多