MailTrackingを使って、Laravelでメール本文や件名のテストを行う

#はじめに

メールのテストをやっていて、
･メール本文のテストをしたい
･メール件名のテストをしたい
といった時、どうしていますか？

現在Laravelで用意されているテストでは、
`assertSent`や`assertQueued`くらいしか使えず、
メールが送信されたかどうかまでしかわかりません。

そこで、もっと詳しくメールのテストができる便利機能
**MailTracking**について書いてみようと思います！

#MailTrackingとは

ざっくり言うと、メールのテストをより詳細に実行できるライブラリです。
メール本文の内容、メール件名、送信者アドレス、送信先アドレス、CC/BCCアドレスなど
様々なテストが可能です。
詳しくは↓
https://github.com/spinen/laravel-mail-assertions/blob/develop/readme.md

##導入方法

超絶簡単！
`$ composer require spinen/laravel-mail-assertions`
これを打ち込むだけ。

また、テストファイルではこんなふうに書いてあげます。
(※その他、メールを送る処理の部分は別途記述が必要ですが、
今回は`MailTracking`のみにフォーカスしています)

```php:

<?php
use Spinen\MailAssertions\MailTracking;

class MailTest extends TestCase
{
    use MailTracking;

    public function testMail()
    {
      //テストを書いていく
    }
```


##使えるアサーション
- seeEmailBcc
- seeEmailCc
- seeEmailContains
- seeEmailContentTypeEquals
- seeEmailCountEquals
- seeEmailDoesNotContain
- seeEmailEquals
- seeEmailFrom
- seeEmailPriorityEquals
- seeEmailReplyTo
- seeEmailSubjectContains
- seeEmailSubjectDoesNotContain
- seeEmailSubjectEquals
- seeEmailTo
- seeEmailWasNotSent
- seeEmailWasSent

それでは見ていきましょう！(ΦωΦ)

##送信先･送信元系
- seeEmailTo
 - 送信先のメールアドレスを確認する 
- seeEmailCc
 - CCに指定されているメールアドレスを確認する 
- seeEmailBcc
 - BCCに指定されているメールアドレスを確認する 
- seeEmailFrom
 - 送信元に指定されているメールアドレスを確認する 
- seeEmailReplyTo
 - 返信先に指定されているメールアドレスを確認する

例えばこんな感じ。
･登録したら登録ユーザーにメールが飛ぶ。(`TO:登録したメールアドレス`)
･かつ、CCで自社にメールを送っている。(`CC:nekocompany_info@example.com`)
･送信元は自社である。(`FROM:nekocompany@example.com`)
こんな時のテストはこう書けばOK。

```php:
$this->post('/register', [
    'email' => 'user@example.com',
]);
$this->seeEmailTo('user@example.com');
$this->seeEmailCC('nekocompany_info@example.com');
$this->seeEmailFrom('nekocompany@example.com');
```
ちなみに、もし宛先が違っていた場合、
下記のようにエラーが出ます。

```
The last email sent was not sent to test@example.com.
Failed asserting that an array has the key 'test@example.com'.
```
(状況：
本当は`user@example.com`に届いているが、
`seeEmailTo('test@example.com')`と書いてしまった。)

※ちょっと注意
実際どのメールアドレスに届いているのか、というのは
エラー文には出ないので、ログで確認する必要があります。

※ちょっと注意2
また、この記事で紹介するアサーションは基本的に、
**2件以上メールを送っている場合、最後に送ったメールしか確認しない**
ことに注意してください。


##内容系
###本文

- seeEmailContains
 - メールの本文に指定文言が含まれていることを確認する(部分一致)
- seeEmailDoesNotContain
 - メールの本文に指定文言が含まれていないことを確認する(部分一致)
- seeEmailEquals
 - メールの本文が指定文言と完全に一致していることを確認する

###件名
- seeEmailSubjectContains
 - メールの件名に指定文言が含まれていることを確認する(部分一致)
- seeEmailSubjectDoesNotContain
 - メールの件名に指定文言が含まれていないことを確認する(部分一致)
- seeEmailSubjectEquals(seeEmailSubjectのみでもOK)
 - メールの件名が指定文言と完全に一致していることを確認する

<br>
例えばメールの内容が下記だった時･･･
~~~~~~~~~~~~~~~~~~~~~~~~~~
`件名:`
【猫カンパニーからのお知らせ】ご登録ありがとうございましたニャ〜
`メール本文:`
猫カンパニーへのご登録、ありがとうございました。
今後ともよろしくお願い致します。
ニャー！
~~~~~~~~~~~~~~~~~~~~~~~~~~

通るように書いたテストはこんな感じです。

```php:
//件名
$this->seeEmailSubjectContains('【猫カンパニーからのお知らせ】');
$this->seeEmailSubjectContains('ニャ〜');
$this->seeEmailSubjectEquals('【猫カンパニーからのお知らせ】ご登録ありがとうございましたニャ〜');
//本文
$this->seeEmailContains('猫カンパニーへのご登録')
$this->seeEmailContains('ニャー！')
$this->seeEmailEquals('猫カンパニーへのご登録、ありがとうございました。
今後ともよろしくお願い致します。
ニャー！');
//ちなみに、改行を含むseeEmailContainsも可能。
//その場合きちんと改行してあげないとエラーになります。
$this->seeEmailContains('致します。
ニャー！')
```

※ちょっと注意点
･エディタを使用している場合、インデントもチェックされるため、
改行後の自動インデントは削除する必要があります。

どういうことかと言うと、、、
こんなふうにテストを書いた時、エラーが出ます。

```php:
//エディタの関係でインデントがある時
        $this->seeEmailEquals('猫カンパニーへのご登録、ありがとうございました。
        今後ともよろしくお願い致します。
        ニャー！');
```

```
The last email sent did not match the given email.
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
 '猫カンパニーへのご登録、ありがとうございました。\n
-        今後ともよろしくお願い致します。\n
-        ニャー！'
+今後ともよろしくお願い致します。\n
+ニャー！'
```

このエラー文は、最初の一行目｢猫カンパニーへのご登録、ありがとうございました。｣までが一致しており、
それ以降は一致していないことを示しています。

また、`Expected`が｢テストで書いた値｣
`Actual`が｢実際に送られているメール｣を指しています。

つまり、｢テストではインデントがあると書いていたけど、実際のメールにはインデントがないよ〜｣
と言っています。
ちょっと見た目が悪くなるかもしれませんが、、、お気をつけください。

##送られたかどうか系
- seeEmailWasNotSent
- seeEmailWasSent

そのとおりメールが送られたかどうか、
または送られていないかどうか調べます。

※ちょっと注意
`seeEmailWasSent`の場合、｢少なくとも1件のメールが送られているか｣の確認をしているので、
何件送られているか確認したい場合は使わない方がベター。

##送られた数系
- seeEmailsSent
- seeEmailCountEquals
 - これら2つとも、何件メールが送られているかを確認します。

もし2件メールを送っている場合はこんな感じ。

```php:
$this->seeEmailsSent(2);
$this->seeEmailCountEquals(2);
```

##その他
- seeEmailPriorityEquals
 - メールのプライオリティ(重要度)を判断する。1〜5の数字が入る。
- seeEmailContentTypeEquals
 - メール形式を確認する。`text/plain`や`text/html`が入る。

このあたりは使用頻度少ないかもしれませんが、一応。

#おわりに
メール内容や件名まで詳細にテストできるMailTracking、かなり便利でした！
調べていると｢本文もテストできたらいいのに｣といった声をちらほら見かけたので
記事にしてみました。

何かご指摘などございましたら、コメントをお願い致します！