- Add Model Mixins: TimestampMixin, SoftDeleteMixin, AuditMixin, etc. - Add Base Services: BaseService, BulkOperationsMixin, QueryOptimizerMixin - Add Base ViewSets with bulk operations - Add BackgroundJob model for Celery task tracking - Add BaseAppCommand for management commands - Add permissions, pagination, filters, cache, logging - Migrate tests to factory_boy + faker - Add CHANGELOG.md - 297 tests passing
292 lines
10 KiB
Python
292 lines
10 KiB
Python
"""Tests for user serializers"""
|
|
|
|
from apps.user.serializers import (
|
|
LoginSerializer,
|
|
PasswordChangeSerializer,
|
|
ProfileUpdateSerializer,
|
|
TokenSerializer,
|
|
UserRegistrationSerializer,
|
|
UserSerializer,
|
|
UserUpdateSerializer,
|
|
)
|
|
from django.contrib.auth import get_user_model
|
|
from django.test import TestCase
|
|
from faker import Faker
|
|
|
|
from .factories import ProfileFactory, UserFactory
|
|
|
|
User = get_user_model()
|
|
fake = Faker("ru_RU")
|
|
|
|
|
|
class UserRegistrationSerializerTest(TestCase):
|
|
"""Tests for UserRegistrationSerializer"""
|
|
|
|
def setUp(self):
|
|
self.password = fake.password(length=12, special_chars=False)
|
|
self.user_data = {
|
|
"email": fake.unique.email(),
|
|
"username": fake.unique.user_name(),
|
|
"password": self.password,
|
|
"password_confirm": self.password,
|
|
"phone": f"+7{fake.numerify('##########')}",
|
|
}
|
|
|
|
def test_valid_registration_data(self):
|
|
"""Test valid registration data"""
|
|
serializer = UserRegistrationSerializer(data=self.user_data)
|
|
self.assertTrue(serializer.is_valid())
|
|
|
|
def test_passwords_do_not_match(self):
|
|
"""Test validation fails when passwords don't match"""
|
|
data = self.user_data.copy()
|
|
data["password_confirm"] = fake.password(length=12, special_chars=False)
|
|
|
|
serializer = UserRegistrationSerializer(data=data)
|
|
|
|
self.assertFalse(serializer.is_valid())
|
|
self.assertIn("non_field_errors", serializer.errors)
|
|
|
|
def test_short_password(self):
|
|
"""Test validation fails with short password"""
|
|
short_password = fake.pystr(min_chars=3, max_chars=5)
|
|
data = self.user_data.copy()
|
|
data["password"] = short_password
|
|
data["password_confirm"] = short_password
|
|
|
|
serializer = UserRegistrationSerializer(data=data)
|
|
|
|
self.assertFalse(serializer.is_valid())
|
|
self.assertIn("password", serializer.errors)
|
|
|
|
def test_duplicate_email(self):
|
|
"""Test validation fails with duplicate email"""
|
|
existing_user = UserFactory.create_user()
|
|
data = self.user_data.copy()
|
|
data["email"] = existing_user.email
|
|
|
|
serializer = UserRegistrationSerializer(data=data)
|
|
|
|
self.assertFalse(serializer.is_valid())
|
|
self.assertIn("email", serializer.errors)
|
|
|
|
def test_duplicate_username(self):
|
|
"""Test validation fails with duplicate username"""
|
|
existing_user = UserFactory.create_user()
|
|
data = self.user_data.copy()
|
|
data["username"] = existing_user.username
|
|
|
|
serializer = UserRegistrationSerializer(data=data)
|
|
|
|
self.assertFalse(serializer.is_valid())
|
|
self.assertIn("username", serializer.errors)
|
|
|
|
def test_create_user(self):
|
|
"""Test user creation through serializer"""
|
|
serializer = UserRegistrationSerializer(data=self.user_data)
|
|
self.assertTrue(serializer.is_valid())
|
|
|
|
user = serializer.save()
|
|
|
|
self.assertIsInstance(user, User)
|
|
self.assertEqual(user.email, self.user_data["email"])
|
|
self.assertEqual(user.username, self.user_data["username"])
|
|
self.assertTrue(user.check_password(self.user_data["password"]))
|
|
|
|
|
|
class UserSerializerTest(TestCase):
|
|
"""Tests for UserSerializer"""
|
|
|
|
def setUp(self):
|
|
self.user = UserFactory.create_user()
|
|
ProfileFactory.create_profile(user=self.user)
|
|
|
|
def test_user_serialization(self):
|
|
"""Test user serialization"""
|
|
serializer = UserSerializer(self.user)
|
|
data = serializer.data
|
|
|
|
self.assertEqual(data["id"], self.user.id)
|
|
self.assertEqual(data["email"], self.user.email)
|
|
self.assertEqual(data["username"], self.user.username)
|
|
self.assertEqual(data["phone"], self.user.phone)
|
|
self.assertEqual(data["is_verified"], self.user.is_verified)
|
|
self.assertIn("profile", data)
|
|
self.assertIn("created_at", data)
|
|
self.assertIn("updated_at", data)
|
|
|
|
def test_read_only_fields(self):
|
|
"""Test that read-only fields are not writable"""
|
|
read_only_fields = ["id", "is_verified", "created_at", "updated_at"]
|
|
serializer = UserSerializer()
|
|
|
|
for field_name in read_only_fields:
|
|
self.assertIn(field_name, serializer.Meta.read_only_fields)
|
|
|
|
|
|
class UserUpdateSerializerTest(TestCase):
|
|
"""Tests for UserUpdateSerializer"""
|
|
|
|
def setUp(self):
|
|
self.user = UserFactory.create_user()
|
|
|
|
def test_valid_update_data(self):
|
|
"""Test valid update data"""
|
|
update_data = {
|
|
"username": fake.unique.user_name(),
|
|
"phone": f"+7{fake.numerify('##########')}",
|
|
}
|
|
|
|
serializer = UserUpdateSerializer(self.user, data=update_data, partial=True)
|
|
self.assertTrue(serializer.is_valid())
|
|
|
|
updated_user = serializer.save()
|
|
self.assertEqual(updated_user.username, update_data["username"])
|
|
self.assertEqual(updated_user.phone, update_data["phone"])
|
|
|
|
def test_fields_allowed(self):
|
|
"""Test only allowed fields can be updated"""
|
|
serializer = UserUpdateSerializer()
|
|
allowed_fields = ["username", "phone"]
|
|
|
|
self.assertEqual(set(serializer.Meta.fields), set(allowed_fields))
|
|
|
|
|
|
class ProfileUpdateSerializerTest(TestCase):
|
|
"""Tests for ProfileUpdateSerializer"""
|
|
|
|
def setUp(self):
|
|
self.user = UserFactory.create_user()
|
|
self.profile = ProfileFactory.create_profile(user=self.user)
|
|
|
|
def test_valid_profile_update_data(self):
|
|
"""Test valid profile update data"""
|
|
update_data = {
|
|
"first_name": fake.first_name(),
|
|
"last_name": fake.last_name(),
|
|
"bio": fake.text(max_nb_chars=200),
|
|
"date_of_birth": str(fake.date_of_birth(minimum_age=18, maximum_age=80)),
|
|
}
|
|
|
|
serializer = ProfileUpdateSerializer(
|
|
self.profile, data=update_data, partial=True
|
|
)
|
|
self.assertTrue(serializer.is_valid())
|
|
|
|
updated_profile = serializer.save()
|
|
self.assertEqual(updated_profile.first_name, update_data["first_name"])
|
|
self.assertEqual(updated_profile.last_name, update_data["last_name"])
|
|
self.assertEqual(updated_profile.bio, update_data["bio"])
|
|
|
|
def test_fields_allowed(self):
|
|
"""Test only allowed fields can be updated"""
|
|
serializer = ProfileUpdateSerializer()
|
|
allowed_fields = ["first_name", "last_name", "bio", "avatar", "date_of_birth"]
|
|
|
|
self.assertEqual(set(serializer.Meta.fields), set(allowed_fields))
|
|
|
|
|
|
class LoginSerializerTest(TestCase):
|
|
"""Tests for LoginSerializer"""
|
|
|
|
def setUp(self):
|
|
self.login_data = {
|
|
"email": fake.email(),
|
|
"password": fake.password(length=12, special_chars=False),
|
|
}
|
|
|
|
def test_valid_login_data(self):
|
|
"""Test valid login data"""
|
|
serializer = LoginSerializer(data=self.login_data)
|
|
self.assertTrue(serializer.is_valid())
|
|
|
|
def test_missing_email(self):
|
|
"""Test validation fails without email"""
|
|
data = {"password": fake.password(length=12, special_chars=False)}
|
|
serializer = LoginSerializer(data=data)
|
|
self.assertFalse(serializer.is_valid())
|
|
self.assertIn("email", serializer.errors)
|
|
|
|
def test_missing_password(self):
|
|
"""Test validation fails without password"""
|
|
data = {"email": fake.email()}
|
|
serializer = LoginSerializer(data=data)
|
|
self.assertFalse(serializer.is_valid())
|
|
self.assertIn("password", serializer.errors)
|
|
|
|
|
|
class TokenSerializerTest(TestCase):
|
|
"""Tests for TokenSerializer"""
|
|
|
|
def test_valid_token_data(self):
|
|
"""Test valid token data"""
|
|
token_data = {
|
|
"access": fake.pystr(min_chars=50, max_chars=100),
|
|
"refresh": fake.pystr(min_chars=50, max_chars=100),
|
|
}
|
|
|
|
serializer = TokenSerializer(data=token_data)
|
|
self.assertTrue(serializer.is_valid())
|
|
|
|
def test_missing_access_token(self):
|
|
"""Test validation fails without access token"""
|
|
data = {"refresh": fake.pystr(min_chars=50, max_chars=100)}
|
|
serializer = TokenSerializer(data=data)
|
|
self.assertFalse(serializer.is_valid())
|
|
self.assertIn("access", serializer.errors)
|
|
|
|
def test_missing_refresh_token(self):
|
|
"""Test validation fails without refresh token"""
|
|
data = {"access": fake.pystr(min_chars=50, max_chars=100)}
|
|
serializer = TokenSerializer(data=data)
|
|
self.assertFalse(serializer.is_valid())
|
|
self.assertIn("refresh", serializer.errors)
|
|
|
|
|
|
class PasswordChangeSerializerTest(TestCase):
|
|
"""Tests for PasswordChangeSerializer"""
|
|
|
|
def setUp(self):
|
|
self.old_password = fake.password(length=12, special_chars=False)
|
|
self.new_password = fake.password(length=12, special_chars=False)
|
|
self.password_data = {
|
|
"old_password": self.old_password,
|
|
"new_password": self.new_password,
|
|
"new_password_confirm": self.new_password,
|
|
}
|
|
|
|
def test_valid_password_change_data(self):
|
|
"""Test valid password change data"""
|
|
serializer = PasswordChangeSerializer(data=self.password_data)
|
|
self.assertTrue(serializer.is_valid())
|
|
|
|
def test_passwords_do_not_match(self):
|
|
"""Test validation fails when new passwords don't match"""
|
|
data = self.password_data.copy()
|
|
data["new_password_confirm"] = fake.password(length=12, special_chars=False)
|
|
|
|
serializer = PasswordChangeSerializer(data=data)
|
|
|
|
self.assertFalse(serializer.is_valid())
|
|
self.assertIn("non_field_errors", serializer.errors)
|
|
|
|
def test_short_new_password(self):
|
|
"""Test validation fails with short new password"""
|
|
short_password = fake.pystr(min_chars=3, max_chars=5)
|
|
data = self.password_data.copy()
|
|
data["new_password"] = short_password
|
|
data["new_password_confirm"] = short_password
|
|
|
|
serializer = PasswordChangeSerializer(data=data)
|
|
|
|
self.assertFalse(serializer.is_valid())
|
|
self.assertIn("new_password", serializer.errors)
|
|
|
|
def test_missing_old_password(self):
|
|
"""Test validation fails without old password"""
|
|
new_password = fake.password(length=12, special_chars=False)
|
|
data = {"new_password": new_password, "new_password_confirm": new_password}
|
|
serializer = PasswordChangeSerializer(data=data)
|
|
self.assertFalse(serializer.is_valid())
|
|
self.assertIn("old_password", serializer.errors)
|