Files
mostovik-backend/tests/apps/core/test_mixins.py
Aleksandr Meshchriakov ee95628a0a
Some checks failed
CI/CD Pipeline / Run Tests (push) Failing after 37s
CI/CD Pipeline / Code Quality Checks (push) Failing after 43s
CI/CD Pipeline / Build & Push Images (push) Has been skipped
CI/CD Pipeline / Deploy (dev) (push) Has been skipped
CI/CD Pipeline / Deploy (prod) (push) Has been skipped
CI/CD Pipeline / Code Quality Checks (pull_request) Failing after 0s
CI/CD Pipeline / Run Tests (pull_request) Failing after 0s
CI/CD Pipeline / Build & Push Images (pull_request) Has been skipped
CI/CD Pipeline / Deploy (dev) (pull_request) Has been skipped
CI/CD Pipeline / Deploy (prod) (pull_request) Has been skipped
feat: обновления парсеров, тестов и миграций
- Обновлены клиенты парсеров (checko, fns, minpromtorg, proverki, zakupki)
- Добавлены новые миграции для моделей
- Расширено покрытие тестами
- Обновлены конфигурации и настройки проекта
- Добавлены утилиты для тестирования

Co-Authored-By: Warp <agent@warp.dev>
2026-02-10 10:17:47 +01:00

208 lines
7.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Тесты для Model Mixins."""
from django.db import connection, models
from django.test import TestCase, TransactionTestCase
from django.test.utils import isolate_apps
from apps.core.mixins import (
AuditMixin,
OrderableMixin,
SlugMixin,
SoftDeleteMixin,
StatusMixin,
TimestampMixin,
)
from tests.apps.user.factories import UserFactory
class TimestampMixinTest(TestCase):
"""Тесты для TimestampMixin."""
def test_created_at_auto_set(self):
"""Проверка автоматической установки created_at."""
# Используем BackgroundJob как пример модели с TimestampMixin
from apps.core.models import BackgroundJob
job = BackgroundJob.objects.create(
task_id="test-task-1",
task_name="test.task",
)
self.assertIsNotNone(job.created_at)
self.assertIsNotNone(job.updated_at)
def test_updated_at_auto_update(self):
"""Проверка автоматического обновления updated_at."""
from apps.core.models import BackgroundJob
job = BackgroundJob.objects.create(
task_id="test-task-2",
task_name="test.task",
)
original_updated = job.updated_at
# Обновляем запись
job.progress = 50
job.save()
job.refresh_from_db()
self.assertGreaterEqual(job.updated_at, original_updated)
class UUIDPrimaryKeyMixinTest(TestCase):
"""Тесты для UUIDPrimaryKeyMixin."""
def test_uuid_auto_generated(self):
"""Проверка автоматической генерации UUID."""
from apps.core.models import BackgroundJob
job = BackgroundJob.objects.create(
task_id="test-task-3",
task_name="test.task",
)
self.assertIsNotNone(job.id)
# Проверяем что ID похож на UUID (строка 32+ символа с дефисами)
self.assertEqual(len(str(job.id)), 36)
def test_uuid_unique(self):
"""Проверка уникальности UUID."""
from apps.core.models import BackgroundJob
job1 = BackgroundJob.objects.create(
task_id="test-task-4a",
task_name="test.task",
)
job2 = BackgroundJob.objects.create(
task_id="test-task-4b",
task_name="test.task",
)
self.assertNotEqual(job1.id, job2.id)
class SoftDeleteMixinTest(TestCase):
"""Тесты для SoftDeleteMixin."""
def test_soft_delete_mixin_fields(self):
"""Проверка наличия полей is_deleted и deleted_at."""
# Проверяем что поля определены в миксине
field_names = [f.name for f in SoftDeleteMixin._meta.get_fields()]
self.assertIn("is_deleted", field_names)
self.assertIn("deleted_at", field_names)
def test_soft_delete_queryset_methods(self):
"""Проверка методов SoftDeleteQuerySet."""
from apps.core.mixins import SoftDeleteQuerySet
# Проверяем что методы определены
self.assertTrue(hasattr(SoftDeleteQuerySet, "alive"))
self.assertTrue(hasattr(SoftDeleteQuerySet, "dead"))
self.assertTrue(hasattr(SoftDeleteQuerySet, "hard_delete"))
class StatusMixinTest(TestCase):
"""Тесты для StatusMixin."""
def test_status_choices(self):
"""Проверка наличия статусов."""
self.assertEqual(StatusMixin.Status.DRAFT, "draft")
self.assertEqual(StatusMixin.Status.ACTIVE, "active")
self.assertEqual(StatusMixin.Status.INACTIVE, "inactive")
self.assertEqual(StatusMixin.Status.ARCHIVED, "archived")
class OrderableMixinTest(TestCase):
"""Тесты для OrderableMixin."""
def test_orderable_mixin_has_order_field(self):
"""Проверка наличия поля order."""
self.assertTrue(hasattr(OrderableMixin, "order"))
@isolate_apps("apps.core")
class MixinsBehaviorTest(TransactionTestCase):
class TestModel(
SoftDeleteMixin,
OrderableMixin,
StatusMixin,
SlugMixin,
AuditMixin,
TimestampMixin,
models.Model,
):
name = models.CharField(max_length=50)
class Meta:
app_label = "core"
@classmethod
def setUpClass(cls):
super().setUpClass()
table_name = cls.TestModel._meta.db_table
existing_tables = connection.introspection.table_names()
with connection.schema_editor() as schema_editor:
if table_name in existing_tables:
schema_editor.delete_model(cls.TestModel)
schema_editor.create_model(cls.TestModel)
@classmethod
def tearDownClass(cls):
table_name = cls.TestModel._meta.db_table
with connection.schema_editor() as schema_editor:
if table_name in connection.introspection.table_names():
schema_editor.delete_model(cls.TestModel)
super().tearDownClass()
def test_soft_delete_and_restore(self):
user = UserFactory.create_user()
obj = self.TestModel.objects.create(
name=f"item-{user.id}",
slug=f"slug-{user.id}",
created_by=user,
)
obj.delete()
self.assertTrue(obj.is_deleted)
self.assertIsNotNone(obj.deleted_at)
self.assertEqual(self.TestModel.objects.count(), 0)
self.assertEqual(self.TestModel.all_objects.count(), 1)
obj.restore()
self.assertFalse(obj.is_deleted)
self.assertEqual(self.TestModel.objects.count(), 1)
def test_soft_delete_queryset_methods(self):
obj = self.TestModel.objects.create(name="alive", slug="alive-slug")
self.TestModel.objects.filter(id=obj.id).delete()
self.assertEqual(self.TestModel.objects.count(), 0)
self.assertEqual(self.TestModel.objects.deleted_only().count(), 1)
def test_hard_delete(self):
obj = self.TestModel.objects.create(name="hard", slug="hard-slug")
obj.hard_delete()
self.assertEqual(self.TestModel.all_objects.count(), 0)
def test_orderable_moves(self):
obj = self.TestModel.objects.create(name="ord", slug="ord-slug", order=2)
obj.move_up()
obj.refresh_from_db()
self.assertEqual(obj.order, 1)
obj.move_down()
obj.refresh_from_db()
self.assertEqual(obj.order, 2)
obj.move_to(5)
obj.refresh_from_db()
self.assertEqual(obj.order, 5)
obj.move_to(-1)
obj.refresh_from_db()
self.assertEqual(obj.order, 5)
def test_status_transitions(self):
obj = self.TestModel.objects.create(name="status", slug="status-slug")
self.assertTrue(obj.is_draft)
obj.activate()
obj.refresh_from_db()
self.assertTrue(obj.is_active_status)
obj.deactivate()
obj.refresh_from_db()
self.assertEqual(obj.status, obj.Status.INACTIVE)
obj.archive()
obj.refresh_from_db()
self.assertTrue(obj.is_archived)