Тестирование почтового уведомления в Laravel без отправки реального письма позволяет проверить логику генерации сообщений, корректность шаблонов и работу вложений в изолированной среде. Это предотвращает засорение почтовых ящиков разработчиков и гарантирует, что ошибки будут обнаружены до попадания письма в сеть.
Тестирование почтового уведомления в Laravel без отправки реального письма
Цель тестирования — убедиться, что письмо формируется корректно: правильный шаблон, нужные переменные подставлены, вложения прикреплены. Реальная отправка на этапе разработки нецелесообразна из-за риска потери данных и нагрузки на SMTP-сервер.
Основной инструмент для этого — смена драйвера почты в конфигурации приложения. Вместо реального SMTP или mailgun используется драйвер 'log', который сохраняет письма в файл, либо 'array', который хранит их в памяти. Дополнительно Laravel предоставляет фреймворк Mail::fake(), который перехватывает все вызовы метода send() и позволяет проверять их через assertions.
Этот подход работает независимо от того, используется ли локальный SMTP или внешний сервис. Он позволяет изолировать логику отправки от инфраструктуры доставки.
Настройка конфигурации для локального тестирования (MAIL_DRIVER)
Первым шагом является изменение переменной MAIL_DRIVER в файле .env. Установите значение log или array.
Если выбран драйвер 'log', письма будут сохраняться в файл storage/logs/mail.log. Это удобно для отладки, так как позволяет просмотреть содержимое писем после завершения теста без необходимости писать специфические проверки в коде.
Драйвер 'array' хранит данные в массиве внутри приложения. Он быстрее, но данные теряются при перезапуске сервера. Подходит для быстрых unit-тестов.
Пример настройки в .env:
Использование встроенного метода Mail::fake() для перехвата писем
Метод Mail::fake() создает мок-объект, который перехватывает все вызовы Mail::send(), Mail::raw() и других методов отправки. Он не требует изменения .env, но должен быть активирован в начале теста.
После выполнения кода отправки письма можно использовать методы assertions для проверки его корректности. Например, assertSent() проверяет, было ли письмо отправлено, и позволяет получить доступ к объекту Mailable.
Пример использования:
Проверка содержимого перехваченных сообщений через assertHasMailable()
Встроенные методы assertions позволяют проверить конкретные свойства письма. Метод assertHasMailable() проверяет наличие определенного класса Mailable в очереди.
Для проверки содержимого используйте assertViewIsRendered(), который подтверждает, что шаблон был сгенерирован корректно и переменные подставлены верно.
Проверка вложений осуществляется через assertHasAttachment(). Это важно для уведомлений, содержащих файлы отчетов или скриншотов.
Пример проверки:
Тестирование с использованием внешних сервисов (например, Mailtrap) при необходимости
Если требуется проверить не только формирование письма, но и его доставку на конкретный адрес или работу SMTP-сервера, используйте внешние сервисы вроде Mailtrap.
Для этого в .env укажите MAIL_HOST и MAIL_PORT сервиса Mailtrap. Письма будут отправляться туда, а вы сможете увидеть их в веб-интерфейсе сервиса.
Это полезно для проверки заголовков письма, SPF/DKIM записей и других технических аспектов доставки, которые не проверяются драйвером 'log'.
Важно: при использовании внешних сервисов убедитесь, что они поддерживают вашу версию PHP и Laravel.
Валидация структуры письма и вложений в тестовой среде
Структура письма включает тему, тело (HTML или текст), заголовки и вложения. Валидация должна проверять все эти компоненты.
Используйте assertThat() для проверки конкретных значений полей, например, темы письма или текста тела.
Для проверки вложений убедитесь, что файл был успешно прикреплен и имеет корректное имя и тип MIME.
Пример комплексной проверки:
Ограничения подхода: отсутствие проверки доставки на стороне SMTP-сервера
Локальное тестирование с драйвером 'log' или Mail::fake() не проверяет работу реального SMTP-сервера. Ошибки подключения, проблемы с DNS, блокировки спам-фильтрами или неверные настройки SPF/DKIM останутся незамеченными.
Если письмо должно отправляться в продакшен, обязательно проводите тесты с реальным SMTP или сервисом перед запуском.
Также не проверяется работа почтового клиента получателя (например, Outlook или Gmail), который может блокировать письма из-за настроек безопасности.
Интеграция тестов в CI/CD пайплайн для автоматической верификации
Автоматизация тестирования писем критически важна для поддержания качества кода. Интегрируйте тесты в CI/CD пайплайн (GitHub Actions, GitLab CI и др.).
Настройте переменные окружения для драйвера 'log' или подключите Mailtrap через секреты репозитория.
При каждом пуше кода запускать тесты отправки писем. Если тест падает, сборка останавливается, и разработчик получает обратную связь сразу.
Это снижает риск попадания дефектов в продакшен.
Вопросы и ответы
Можно ли использовать Mail::fake() вместе с драйвером 'smtp'?
Да, но только если переменная MAIL_MAILER не установлена или явно указана как 'log'. Если установлен реальный SMTP, фейк может не сработать корректно. Лучше явно указать MAIL_DRIVER=log в .env при тестировании.
Как проверить письмо, отправленное через очередь (queue)?
Для этого нужно использовать драйвер 'sync' или 'database' для очереди, а также активировать Mail::fake(). Laravel автоматически перехватит сообщение из очереди и сохранит его в логе.
Что делать, если письмо не попадает в лог?
Проверьте права доступа к файлу storage/logs/mail.log. Убедитесь, что драйвер почты действительно установлен как 'log' в .env и что код отправки письма вызывается внутри теста.
По теме
<?php
use Illuminate\Support\Facades\Mail;
use Tests\TestCase;
class MailTest extends TestCase
{
public function test_email_is_sent_correctly()
{
Mail::fake();
$message = Mail::raw('Это тестовое письмо', function ($m) {
$m->to('test@example.com')->subject('Тест');
});
Mail::assertSent(
\App\Mail\TestEmail::class,
function ($muse) use ($message) {
return $muse->hasSubject('Тест') && $muse->hasBody('Это тестовое письмо');
}
);
}
}