LoginSignup
11
4

More than 5 years have passed since last update.

E2Eテストでメールを扱う

Last updated at Posted at 2018-12-11

こんにちは。皆さんE2Eテスト書いてますか?
今回は自分がリグレッションテストの自動化に取り組む中で、特に自動化による恩恵が大きかった「メール周りのテスト自動化」について紹介したいと思います。

やりたかったこと

ユーザー新規登録のE2Eテストを自動化したかったのですが、登録時にメールで送信される認証URLを受け取る必要がありました。
「登録時にユーザーにメールが送信される」という部分も自動テストで担保したかったので、ちゃんとメール送信を確認できるようにしたかった感じです。

どうしたか

弊社ではメール送信にMandrill を利用しています。
MandrillにはTestModeという機能があり、要はSandboxなのですが、「テスト用のAPIキーを使って送信したメールは実際に送信されることはない」という機能です。名前の通りテストに最適です。

image.png

こんな感じのイメージです。

やってみよう

Mandrillの登録とかそういうのは本筋から逸れるんで省略します。ごめんなさい。

MandrillのTestModeをONにする

右上のアカウント名のところをクリックすると Turn on Test Mode というボタンが出てくるのでクリックします。

image.png

全体的に黄色い感じになりましたね。

image.png

テスト用APIキーを取得する

Settings > New API Key からAPIキーを作成します。

image.png

このとき、必ず Test Key にチェックを入れて下さい。

image.png

アプリからメールを送信する

上記で取得したAPI Keyを使ってメールを送信してください。
お使いのフレームワークなりでMandrill対応していればそのフレームワークのドキュメントを読んでもらうのが良いでしょうし、SMTPのパスワードにAPI Keyを入れてもOKです。

送信すると、Outboundタブからメールが見れるようになります。反映まで20〜30秒くらい時間がかかるようです。

送信したメールをAPIで確認する

Mandrill APIにはSDKが用意されているので、ありがたく使わせて頂きましょう。以下はNodeJSのサンプルです。検索結果から直近1件の明細を取得します。

import { Mandrill } from 'mandrill-api';
import * as sleep from 'sleep-promise'

async function fetchOne(query, api_key) {
    const client = new Mandrill(api_key)
    const search = (query, api_key) => {
        return new Promise((resolve, reject) => {
            client.messages.search(
                {
                    query,
                    api_key,
                    limit: 100
                },
                result => {
                    resolve(result)
                }, 
                err => {
                    reject(err)
                }
            )
        })
    }
    let searchResult = await search(query, api_key)
    for (var i = 0; i < 10; i++) {
        if (searchResult['length'] === 0) {
            await sleep(10000)
            searchResult = await search(query, api_key)
        }
    }

    return new Promise((resolve, reject) => {
        client.messages.content(
            {
                id: searchResult[0]._id
            },
            result => {
                resolve(result)
            },
            err => {
                reject(err)
            },
        )
    })
}

前項でも書きましたが、メールを送ってからMandrillで確認できるようになるまで20〜30秒ほど時間がかかるので、何度かリトライするようにしています。
大まかな処理の流れとしては

  • searchでメールを検索する
  • 1件以上結果が返ってくるまでリトライする
  • 1件以上返ってきたら、メッセージIDをもとに messages.content を叩く

messages.content は非同期で返ってくるので、Promiseを返すようにしています。

fetchOne() の引数 query に指定するクエリは https://mandrill.zendesk.com/hc/en-us/articles/205583137-How-to-Search-Outbound-Activity-in-Mandrill を参照してください。例えば、「hoge@example.com 宛かつ件名が ユーザー登録完了のお願い」であれば下記のようになります。


query = 'full_email:hoge@example.com AND subject:ユーザー登録完了のお願い'

戻り値をどうにかする

上記のサンプルを使って実際にメールを受け取ってみましょう。

console.log(await mail.fetchOne("full_email:hoge@example.com AND subject:ユーザー登録完了のお願い'"))

すると、こんな感じのJSONが出力されます。

{
  "headers": {
    "Message-Id": "<2527db4835f0d47904dd1a28fb8afc85@swift.generated>",
    "Date": "Tue, 11 Dec 2018 15:51:43 +0900",
    "From": "webmaster@example.com",
    "To": "hoge@example.com",
    "Mime-Version": "1.0",
    "Content-Type": "text/html; charset=utf-8",
    "Content-Transfer-Encoding": "quoted-printable"
  },
  "html": "(省略)",
  "from_email": "webmaster@example.com",
  "from_name": "webmaster",
  "to": { "email": "hoge@example.com", "name": "" },
  "subject": "ユーザー登録完了のお願い",
  "attachments": [],
  "text": "(省略)",
  "ts": 1544511103,
  "tags": [],
  "_id": "61aa5497443d485a9747f1af8ab3d0d1"
}

メール本文は htmltext に入りますので、ここをパースすれば今回の目的である認証URLが取得できます。
注意点として、 html に入るURLはMandrill経由でリダイレクトされるURLになっていますので、特別な理由がなければ text から取るのが良いでしょう。

おわりに

メール周りは手動テストするのもめんどくさいので、自動化で楽しやすい部分ですね!みなさんもどんどんやってみてください!

11
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
4