В данный момент работаю на проекте Wedding Spot. И важной частью функционала является - email.
Проблема
И несколько раз у нас были проблемы когда воркер серверы которые отправляют емейлы - падали и очень много емейлов не доходили до клиентов, или с определенным опозданием ( что не есть хорошо).
Руками тестировать это сложно ( долго/ неинтересно/ скучно).
Выбор Gmail
Так как раньше уже пробовал тестировать емейлы - и раз решил воспользоваться Gmail.
Все тесты пишу на #python #pytest + #selenium и запускаю через #travisci.
Настройка Gmail
Создаем любой Gmail аккаунт и в настройках для него включаем возможность доступа для
Less secure app access
Тестовый сценарий
Моя реализация не является идеальной и не совсем гибкой. Но она достаточно стабильная. Так что готов принять критику.
Суть одного из тестов заключается в том,
- Я логинюсь на наш сайт с помощью email (gmail) + password. (Couple)
- Открываю необходимую мне страницу
- Пишу сообщение.
- Делаю логин через #api на #gmail аккаунт пользователя которому писал сообщение (Venue)
- Проверяю что сообщение пришло.
- Отвечаю через #email
- Захожу на #gmail аккаунт пользователя который писал сообщение через UI (Couple)
- Проверяю ответ.
Реализация
Делаю очень просто ( и не очень гибко, что можно было бы переписать но пока руки не дошли).
Перед самим тестом - очищаю все входящие сообщения для двух аккаунтов (Couple + Venue )
И вот пару методов ( который нашел на просторах #stackoverflow ) и оптимизировал под свои нужды.
Первый емейл на который идет reply - должен приходить в течении минуты. По - этому реализовано все по хардкору - ждем 60 секунд и запрашиваем последний емейл.
import imaplib
import time
import email
from email.parser import Parser
import smtplib
import re
from bs4 import BeautifulSoup
SMTP_SERVER = "imap.gmail.com"
SMTP_PORT = 993
class Email(object):
def __init__(self, email, password):
self.login_email = email
self.smtp_server = SMTP_SERVER
self.password = password
def read_last_email(self):
"""
Get last inbox email and return it as string
:return: string
"""
try:
mail = imaplib.IMAP4_SSL('imap.gmail.com')
mail.login(self.login_email, self.password)
mail.list()
# Out: list of "folders" aka labels in gmail.
mail.select("inbox") # connect to inbox.
result, data = mail.search(None, "ALL")
ids = data[0] # data is a list.
id_list = ids.split() # ids is a space separated string
latest_email_id = id_list[-1] # get the latest
result, data = mail.fetch(latest_email_id, "(RFC822)") # fetch the email body (RFC822) for the given ID
raw_email = data[0][1] # here's the body, which is raw text of the whole email
# including headers and alternate payloads
convert_email_to_text = email.message_from_bytes(raw_email)
a = convert_email_to_text.get_payload()[0]
remove_r = str(a).replace('\r', '')
return remove_r.replace('\n', '')
except Exception as e:
print(str(e))
def delete_all_email(self):
"""
Remove all emails
"""
mail = imaplib.IMAP4_SSL('imap.gmail.com')
mail.login(self.login_email, self.password)
mail.list()
# Out: list of "folders" aka labels in gmail.
mail.select("inbox") # connect to inbox.
typ, data = mail.search(None, 'ALL')
for num in data[0].split():
mail.store(num, '+FLAGS', '\\Deleted')
mail.expunge()
Для второго случая нужно более гибкое ожидание.
Ждем необходимое сообщение expected_string ждем timeout и проверяем каждых poll секунд.
def wait_for_email_with_text(email, password, expected_string, timeout=150, poll=10):
start_time = time.time()
while (time.time() - start_time) < timeout:
last_email = Email(email, password).read_last_email()
if expected_string in last_email:
return True
else:
time.sleep(poll)
return False
timeout - время ожидания нужного мне емейла, а poll - как часто я проверяю.
на практике я использую timeout=7200;poll=150
Итоги
Я показал частный случай тестирования Gmail. Он имеет свои плюсы и минусы. В моем случае он полностью перекрывает все поставленные задачи. Легко настроить и быстро начать использовать.