В этой статье мы рассмотрим, как протестировать djoser при использовании активации электронной почты для ваших пользователей.
Требования
- Вы уже используете djoser в своем приложении.
Итак, вы используете django, django restframework и djoser с email активацией, но испытываете трудности с тестированием аутентификации? Что ж, давайте немного разберемся с этой проблемой.
Прежде всего, нам нужно разделить наш файл настроек на production, development и testing. Структура выглядит следующим образом
settings/
__init__.py
base.py
production.py
development.py
testing.py
Первое, что мы должны сделать, это создать папку внутри вашего основного проекта под названием settings
. Внимательно отнеситесь к названию папки, оно должно быть точно таким же, как settings.py
, но без .py
.
Далее мы создаем следующие файлы
__init__.py
base.py
production.py
development.py
testing.py
Эти файлы используются в соответствии с названием, в разработке настройки django используют development.py
, в тестировании — testing.py
и так далее.
Теперь давайте скопируем общие настройки для всего проекта в base.py
. Вы сами должны определить, что является общим для всего проекта.
В моем случае, для base.py
я поместил следующее
BASE_DIR
SECRET_KEY # read from environment variable
INSTALLED_APPS
MIDDLEWARE
ROOT_URLCONF
TEMPLATES
WSGI_APPLICATION
AUTH_PASSWORD_VALIDATORS
LANGUAGE_CODE
TIME_ZONE
USE_I18N
USE_TZ
STATIC_URL
DEFAULT_AUTO_FIELD
AUTH_USER_MODEL
# emial related parameter are read from env in my case
EMAIL_BACKEND
EMAIL_HOST
EMAIL_PORT
EMAIL_HOST_USER
EMAIL_HOST_PASSWORD
EMAIL_USE_TLS
REST_FRAMEWORK # depends on your choice of drf settings
DJOSER # common setting only we will extend it in other files
для production.py
from .base import *
DEBUG = False
ALLOWED_HOSTS = ['yoursite.com'] # up to you choice what to allow
DATABASES # i use different db for prod
DJOSER.update({
....
}) # i use different conf for prod
для development.py
from .base import *
DEBUG = True
ALLOWED_HOSTS = ['*'] # up to you choice what to allow
DATABASES # i use different db for dev
DJOSER.update({
....
}) # i use different conf for dev
для testing.py
мы рассмотрим этот файл подробнее, а пока
from .base import *
DEBUG = True
ALLOWED_HOSTS = ['*'] # up to you choice what to allow
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
DATABASES # i use different db for test
DJOSER.update({
....
}) # i use different conf for test
Теперь последний файл __init__.py
.
этот файл динамически загружает настройки
import os
from . import base
enviroment = os.environ.get('ENVIROMENT', 'development')
if enviroment == 'production':
from .production import *
elif enviroment == 'testing':
from .testing import *
else:
from .development import *
Djoser использует различные классы сериализаторов для различных целей, но мы сосредоточимся только на Email сериализаторах, посмотрите документацию.
Итак, теперь давайте напишем файл testing.py
.
from .base import *
DEBUG = True
ALLOWED_HOSTS = ['*']
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
# }
# for postgresql: i use postgres
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'djoser',
'USER': 'djoser',
'PASSWORD': 'djoser',
'HOST': 'localhost',
'PORT': '5432',
}
# for mysql:
# 'default': {
# 'ENGINE': 'django.db.backends.mysql',
# 'NAME': 'djoser',
# 'USER': 'djoser',
# 'PASSWORD': 'djoser',
# 'HOST': 'localhost',
# 'PORT': '3306',
# }
}
DJOSER_EMAIL = {
'activation': 'your-authentication-app.email.ActivationEmail'
}
if 'EMAIL' in DJOSER:
DJOSER['EMAIL'].update(DJOSER_EMAIL)
else:
DJOSER['EMAIL'] = DJOSER_EMAIL
если вы заметили в
DJOSER_EMAIL = {
'activation': 'your-authentication-app.email.ActivationEmail'
}
мы переопределим сериализатор активации электронной почты с помощью your-authentication-app.email.ActivationEmail
, но он еще не существует, поэтому давайте создадим его сейчас.
В вашем приложении аутентификации создайте файл email.py
и поместите в него нижеприведенный сериализатор, и давайте поговорим об этом.
from django.contrib.auth.tokens import default_token_generator
# djoser imports
from templated_mail.mail import BaseEmailMessage
from djoser import utils
from djoser.conf import settings
EMAILS = {}
class ActivationEmail(BaseEmailMessage):
"""Email Activation Token Generator
"""
template_name = "email/activation.html"
def get_context_data(self):
# ActivationEmail can be deleted
context = super().get_context_data()
user = context.get("user")
context["uid"] = utils.encode_uid(user.pk)
context["token"] = default_token_generator.make_token(user)
context["url"] = settings.ACTIVATION_URL.format(**context)
uid, token = context['uid'], context['token']
# here we store all the requested tokens in a dictionary for later use
EMAILS[user.email] = {'uid': uid, 'token': token}
return context
Единственное, что мы добавляем из сериализатора djoser, это
EMAIL = {}
...
EMAILS[user.email] = {'uid': uid, 'token': token}
Они используются для хранения электронной почты, отправленной с нашего сервера.
ПРИМЕЧАНИЕ: мы используем EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
, потому что во время тестирования мы не хотим, чтобы django отправлял реальные письма.
Теперь мы собираемся протестировать наших пользователей. Вот несколько примеров для тестирования, но в то же время вы сами можете решить, что тестировать
from django.urls import reverse
from django.contrib.auth import get_user_model
from rest_framework import status
from rest_framework.test import APITestCase
User = get_user_model()
class UserViewSetTest(APITestCase):
def setUp(self):
"""
Set up method which is used to initialize before any test run.
"""
self.user_info = self.generate_user_info()
def generate_user_info(self):
"""Generate user data for new user.
Returns:
Dict: dictionary of the test user data.
"""
return {
"first_name": "fake.first_name()",
"last_name": "fake.last_name()",
"username": "fake.user_name()",
"password": "fake.password()",
}
def test_create_user(self):
"""
Test for creating users using API.
"""
url = reverse("user-list")
response = self.client.post(
url,
self.user_info,
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
user = User.objects.get(id=response.data['id'])
self.assertEqual(user.email, self.user_info["email"])
self.assertEqual(user.username, self.user_info["username"])
# self.assertEqual(user.ssn, self.user_info["ssn"])
self.assertTrue(user.password is not self.user_info["password"])
self.assertTrue(user.is_deleted is not True)
self.assertTrue(user.father_first_name is None)
self.assertTrue(user.mother_first_name is None)
self.assertTrue(user.password is not None)
self.assertTrue(user.birth_date is not None)
def test_get_token(self):
"""
This test is used to test the login API. getting token and testing the token.
"""
# Create a new user to login
user_info = self.generate_user_info()
new_user = self.client.post(
reverse("user-list"),
user_info,
)
self.assertEqual(new_user.status_code, status.HTTP_201_CREATED)
# Activation of User
from authentications.email import EMAILS
activation_url = reverse('user-activation')
activation_data = EMAILS[user_info["email"]]
self.client.post(activation_url, activation_data)
url = reverse("jwt-create")
data = {
"username": user_info["username"],
"password": user_info["password"],
}
response = self.client.post(url, data)
self.assertTrue(response.status_code, status.HTTP_200_OK)
self.assertTrue(response.data["access"] is not None)
def test_get_user(self):
"""
This test for retrieving single user using API.
"""
# Create a new user to login
new_user = self.client.post(
reverse("user-list"),
self.user_info,
)
self.assertEqual(new_user.status_code, status.HTTP_201_CREATED)
# Activate User
from authentications.email import EMAILS
activation_url = "http://127.0.0.1:8000/auth/users/activation/"
activation_data = EMAILS[self.user_info["email"]]
self.client.post(activation_url, activation_data)
# Get token
url = reverse("jwt-create")
data = {
"username": self.user_info["username"],
"password": self.user_info["password"],
}
response = self.client.post(url, data)
self.assertTrue(response.status_code, status.HTTP_200_OK)
# Get user
token = response.data["access"]
self.client.credentials(HTTP_AUTHORIZATION=f"JWT {token}")
url = reverse('user-list', kwargs={'id':new_user.data["id"]})
get_user = self.client.get(url)
self.assertEqual(get_user.status_code, status.HTTP_200_OK)
self.assertEqual(get_user.data["id"], new_user.data["id"])
self.assertEqual(get_user.data["email"], new_user.data["email"])
test_user = self.client.post(
reverse("user-list"),
self.generate_user_info(),
)
url = url = reverse('user-list', kwargs={'id': test_user.data['id'] })
get_user = self.client.get(url)
self.assertEqual(get_user.status_code, status.HTTP_404_NOT_FOUND)
Есть разные виды тестов, но главная цель этого блога — дать вам знать, как протестировать djoser с включенной активацией электронной почты.
Надеюсь, это поможет вам.
Наслаждайтесь.