Добавлены интеграционные тесты создания тенантов
Создан файл tenants/tests/test_tenant_creation.py с 7 E2E тестами:
1. test_new_tenant_gets_all_5_payment_methods (КРИТИЧЕСКИЙ)
- Проверяет что новый тенант получает все 5 способов оплаты
- Включая account_balance (основной баг который исправили)
- Проверяет правильность порядка, флагов, названий
2. test_new_tenant_gets_order_statuses
- Проверяет создание системных статусов заказов
- Минимум 3 статуса (draft, completed и другие)
3. test_new_tenant_gets_system_customer
- Проверяет создание системного клиента
- Для анонимных продаж
4. test_new_tenant_gets_superuser
- Проверяет создание суперпользователя
- С email из настроек TENANT_ADMIN_EMAIL
5. test_new_tenant_gets_domain
- Проверяет создание домена
- Формат: {schema_name}.localhost
6. test_registration_status_changes_to_approved
- Проверяет изменение статуса заявки
- PENDING → APPROVED
7. test_complete_tenant_onboarding (КОМПЛЕКСНЫЙ E2E)
- Проверяет весь процесс онбординга
- Все предыдущие проверки в одном тесте
- Красивый вывод результата в консоль
Особенности:
- TransactionTestCase для работы с реальными схемами
- Создание администратора в setUp для каждого теста
- Автоматическая очистка схем в tearDown
- Вызов реального метода _approve_registration из админки
- Полное тестирование процесса как в продакшене
Результат: 2 главных теста прошли успешно ✓
test_new_tenant_gets_all_5_payment_methods: OK (10s)
test_complete_tenant_onboarding: OK (9.5s)
This commit is contained in:
4
myproject/tenants/tests/__init__.py
Normal file
4
myproject/tenants/tests/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Тесты для приложения tenants
|
||||
"""
|
||||
365
myproject/tenants/tests/test_tenant_creation.py
Normal file
365
myproject/tenants/tests/test_tenant_creation.py
Normal file
@@ -0,0 +1,365 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Интеграционные тесты создания тенантов.
|
||||
|
||||
Проверяем полный процесс онбординга нового тенанта:
|
||||
1. Создание схемы БД
|
||||
2. Создание домена
|
||||
3. Создание суперпользователя
|
||||
4. Создание способов оплаты
|
||||
5. Создание системных статусов заказов
|
||||
6. Создание системного клиента
|
||||
"""
|
||||
from django.test import TestCase, TransactionTestCase
|
||||
from django.db import connection
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.conf import settings
|
||||
from django_tenants.utils import schema_context
|
||||
|
||||
from tenants.models import Client, Domain, TenantRegistration
|
||||
from orders.models import PaymentMethod, OrderStatus
|
||||
from customers.models import Customer
|
||||
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class TenantCreationIntegrationTest(TransactionTestCase):
|
||||
"""
|
||||
Интеграционный тест полного процесса создания тенанта.
|
||||
|
||||
TransactionTestCase используется потому что:
|
||||
1. Нужно создавать реальные схемы БД
|
||||
2. Нужно переключаться между схемами
|
||||
3. Нужно очищать созданные схемы после теста
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
"""Подготовка к каждому тесту"""
|
||||
# Создаём администратора для каждого теста
|
||||
self.admin_user = User.objects.create_superuser(
|
||||
email='test_admin_per_test@example.com',
|
||||
password='testpass123',
|
||||
name='Test Admin'
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
"""Очистка после каждого теста"""
|
||||
# Удаляем все тестовые тенанты и их схемы
|
||||
test_tenants = Client.objects.filter(schema_name__startswith='test_shop_')
|
||||
|
||||
for tenant in test_tenants:
|
||||
schema_name = tenant.schema_name
|
||||
|
||||
# Удаляем схему вручную
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute(f'DROP SCHEMA IF EXISTS {schema_name} CASCADE')
|
||||
|
||||
# Удаляем запись тенанта
|
||||
tenant.delete()
|
||||
|
||||
# Удаляем тестовые заявки
|
||||
TenantRegistration.objects.filter(schema_name__startswith='test_shop_').delete()
|
||||
|
||||
def test_new_tenant_gets_all_5_payment_methods(self):
|
||||
"""
|
||||
КРИТИЧЕСКИЙ ТЕСТ: Новый тенант автоматически получает все 5 способов оплаты.
|
||||
|
||||
Это главный тест для проверки исправления бага с отсутствием account_balance.
|
||||
"""
|
||||
# 1. Создаём заявку на регистрацию
|
||||
registration = TenantRegistration.objects.create(
|
||||
shop_name='Тестовый магазин',
|
||||
schema_name='test_shop_payment',
|
||||
owner_email='owner@test.com',
|
||||
owner_name='Тест Владелец',
|
||||
phone='+375291111111',
|
||||
status=TenantRegistration.STATUS_PENDING
|
||||
)
|
||||
|
||||
# 2. Активируем заявку (как в админке)
|
||||
from tenants.admin import TenantRegistrationAdmin
|
||||
from django.contrib.admin.sites import AdminSite
|
||||
|
||||
admin = TenantRegistrationAdmin(TenantRegistration, AdminSite())
|
||||
tenant = admin._approve_registration(registration, self.admin_user)
|
||||
|
||||
# 3. Проверяем что тенант создан
|
||||
self.assertIsNotNone(tenant)
|
||||
self.assertEqual(tenant.schema_name, 'test_shop_payment')
|
||||
|
||||
# 4. Переключаемся на схему нового тенанта
|
||||
with schema_context('test_shop_payment'):
|
||||
# 5. ГЛАВНАЯ ПРОВЕРКА: Все 5 способов оплаты созданы
|
||||
payment_methods = PaymentMethod.objects.all().order_by('order')
|
||||
|
||||
self.assertEqual(
|
||||
payment_methods.count(),
|
||||
5,
|
||||
f"Ожидалось 5 способов оплаты, получено {payment_methods.count()}"
|
||||
)
|
||||
|
||||
# 6. Проверяем каждый способ оплаты по отдельности
|
||||
expected_methods = [
|
||||
('account_balance', 'С баланса счёта', 0),
|
||||
('cash', 'Наличными', 1),
|
||||
('card', 'Картой', 2),
|
||||
('online', 'Онлайн', 3),
|
||||
('legal_entity', 'Безнал от ЮРЛИЦ', 4),
|
||||
]
|
||||
|
||||
for code, name, order in expected_methods:
|
||||
method = PaymentMethod.objects.filter(code=code).first()
|
||||
|
||||
self.assertIsNotNone(
|
||||
method,
|
||||
f"Способ оплаты '{code}' не создан!"
|
||||
)
|
||||
|
||||
self.assertEqual(method.name, name)
|
||||
self.assertEqual(method.order, order)
|
||||
self.assertTrue(method.is_system)
|
||||
self.assertTrue(method.is_active)
|
||||
|
||||
# 7. Проверяем что account_balance на первом месте
|
||||
first_method = payment_methods.first()
|
||||
self.assertEqual(
|
||||
first_method.code,
|
||||
'account_balance',
|
||||
f"Первый способ оплаты должен быть 'account_balance', но получен '{first_method.code}'"
|
||||
)
|
||||
|
||||
def test_new_tenant_gets_order_statuses(self):
|
||||
"""
|
||||
Тест: Новый тенант получает системные статусы заказов.
|
||||
"""
|
||||
# Создаём и активируем тенант
|
||||
registration = TenantRegistration.objects.create(
|
||||
shop_name='Тестовый магазин статусы',
|
||||
schema_name='test_shop_statuses',
|
||||
owner_email='owner2@test.com',
|
||||
owner_name='Тест Владелец 2',
|
||||
phone='+375291111112',
|
||||
status=TenantRegistration.STATUS_PENDING
|
||||
)
|
||||
|
||||
from tenants.admin import TenantRegistrationAdmin
|
||||
from django.contrib.admin.sites import AdminSite
|
||||
|
||||
admin = TenantRegistrationAdmin(TenantRegistration, AdminSite())
|
||||
tenant = admin._approve_registration(registration, self.admin_user)
|
||||
|
||||
# Проверяем статусы заказов
|
||||
with schema_context('test_shop_statuses'):
|
||||
statuses = OrderStatus.objects.all()
|
||||
|
||||
# Должно быть минимум 3 основных статуса
|
||||
self.assertGreaterEqual(
|
||||
statuses.count(),
|
||||
3,
|
||||
"Должно быть создано минимум 3 системных статуса"
|
||||
)
|
||||
|
||||
# Проверяем наличие ключевых статусов
|
||||
draft_status = OrderStatus.objects.filter(code='draft').first()
|
||||
self.assertIsNotNone(draft_status, "Статус 'draft' не создан")
|
||||
self.assertTrue(draft_status.is_system)
|
||||
|
||||
completed_status = OrderStatus.objects.filter(code='completed').first()
|
||||
self.assertIsNotNone(completed_status, "Статус 'completed' не создан")
|
||||
self.assertTrue(completed_status.is_system)
|
||||
|
||||
def test_new_tenant_gets_system_customer(self):
|
||||
"""
|
||||
Тест: Новый тенант получает системного клиента для анонимных продаж.
|
||||
"""
|
||||
# Создаём и активируем тенант
|
||||
registration = TenantRegistration.objects.create(
|
||||
shop_name='Тестовый магазин клиенты',
|
||||
schema_name='test_shop_customers',
|
||||
owner_email='owner3@test.com',
|
||||
owner_name='Тест Владелец 3',
|
||||
phone='+375291111113',
|
||||
status=TenantRegistration.STATUS_PENDING
|
||||
)
|
||||
|
||||
from tenants.admin import TenantRegistrationAdmin
|
||||
from django.contrib.admin.sites import AdminSite
|
||||
|
||||
admin = TenantRegistrationAdmin(TenantRegistration, AdminSite())
|
||||
tenant = admin._approve_registration(registration, self.admin_user)
|
||||
|
||||
# Проверяем системного клиента
|
||||
with schema_context('test_shop_customers'):
|
||||
system_customer = Customer.objects.filter(is_system_customer=True).first()
|
||||
|
||||
self.assertIsNotNone(
|
||||
system_customer,
|
||||
"Системный клиент не создан"
|
||||
)
|
||||
|
||||
self.assertTrue(system_customer.is_system_customer)
|
||||
self.assertEqual(system_customer.name, 'Анонимный клиент')
|
||||
|
||||
def test_new_tenant_gets_superuser(self):
|
||||
"""
|
||||
Тест: Новый тенант получает суперпользователя для доступа к админке.
|
||||
"""
|
||||
# Создаём и активируем тенант
|
||||
registration = TenantRegistration.objects.create(
|
||||
shop_name='Тестовый магазин админ',
|
||||
schema_name='test_shop_admin',
|
||||
owner_email='owner4@test.com',
|
||||
owner_name='Тест Владелец 4',
|
||||
phone='+375291111114',
|
||||
status=TenantRegistration.STATUS_PENDING
|
||||
)
|
||||
|
||||
from tenants.admin import TenantRegistrationAdmin
|
||||
from django.contrib.admin.sites import AdminSite
|
||||
|
||||
admin = TenantRegistrationAdmin(TenantRegistration, AdminSite())
|
||||
tenant = admin._approve_registration(registration, self.admin_user)
|
||||
|
||||
# Проверяем суперпользователя
|
||||
with schema_context('test_shop_admin'):
|
||||
superuser = User.objects.filter(
|
||||
email=settings.TENANT_ADMIN_EMAIL
|
||||
).first()
|
||||
|
||||
self.assertIsNotNone(
|
||||
superuser,
|
||||
f"Суперпользователь с email {settings.TENANT_ADMIN_EMAIL} не создан"
|
||||
)
|
||||
|
||||
self.assertTrue(superuser.is_superuser)
|
||||
self.assertTrue(superuser.is_staff)
|
||||
|
||||
def test_new_tenant_gets_domain(self):
|
||||
"""
|
||||
Тест: Новый тенант получает домен для доступа.
|
||||
"""
|
||||
# Создаём и активируем тенант
|
||||
registration = TenantRegistration.objects.create(
|
||||
shop_name='Тестовый магазин домен',
|
||||
schema_name='test_shop_domain',
|
||||
owner_email='owner5@test.com',
|
||||
owner_name='Тест Владелец 5',
|
||||
phone='+375291111115',
|
||||
status=TenantRegistration.STATUS_PENDING
|
||||
)
|
||||
|
||||
from tenants.admin import TenantRegistrationAdmin
|
||||
from django.contrib.admin.sites import AdminSite
|
||||
|
||||
admin = TenantRegistrationAdmin(TenantRegistration, AdminSite())
|
||||
tenant = admin._approve_registration(registration, self.admin_user)
|
||||
|
||||
# Проверяем домен
|
||||
domain = Domain.objects.filter(tenant=tenant).first()
|
||||
|
||||
self.assertIsNotNone(domain, "Домен не создан")
|
||||
self.assertEqual(
|
||||
domain.domain,
|
||||
'test_shop_domain.localhost',
|
||||
f"Ожидался домен 'test_shop_domain.localhost', получен '{domain.domain}'"
|
||||
)
|
||||
self.assertTrue(domain.is_primary)
|
||||
|
||||
def test_registration_status_changes_to_approved(self):
|
||||
"""
|
||||
Тест: После активации статус заявки меняется на APPROVED.
|
||||
"""
|
||||
# Создаём заявку
|
||||
registration = TenantRegistration.objects.create(
|
||||
shop_name='Тестовый магазин статус',
|
||||
schema_name='test_shop_status',
|
||||
owner_email='owner6@test.com',
|
||||
owner_name='Тест Владелец 6',
|
||||
phone='+375291111116',
|
||||
status=TenantRegistration.STATUS_PENDING
|
||||
)
|
||||
|
||||
# Проверяем начальный статус
|
||||
self.assertEqual(registration.status, TenantRegistration.STATUS_PENDING)
|
||||
|
||||
# Активируем
|
||||
from tenants.admin import TenantRegistrationAdmin
|
||||
from django.contrib.admin.sites import AdminSite
|
||||
|
||||
admin = TenantRegistrationAdmin(TenantRegistration, AdminSite())
|
||||
tenant = admin._approve_registration(registration, self.admin_user)
|
||||
|
||||
# Обновляем объект из БД
|
||||
registration.refresh_from_db()
|
||||
|
||||
# Проверяем изменённый статус
|
||||
self.assertEqual(registration.status, TenantRegistration.STATUS_APPROVED)
|
||||
self.assertIsNotNone(registration.processed_at)
|
||||
self.assertEqual(registration.processed_by, self.admin_user)
|
||||
self.assertEqual(registration.tenant, tenant)
|
||||
|
||||
def test_complete_tenant_onboarding(self):
|
||||
"""
|
||||
КОМПЛЕКСНЫЙ ТЕСТ: Проверяем весь процесс онбординга тенанта.
|
||||
|
||||
Это E2E тест, который проверяет что при создании нового тенанта
|
||||
создаются ВСЕ необходимые сущности.
|
||||
"""
|
||||
# Создаём и активируем тенант
|
||||
registration = TenantRegistration.objects.create(
|
||||
shop_name='Полный тестовый магазин',
|
||||
schema_name='test_shop_complete',
|
||||
owner_email='owner_complete@test.com',
|
||||
owner_name='Тест Владелец Полный',
|
||||
phone='+375291111117',
|
||||
status=TenantRegistration.STATUS_PENDING
|
||||
)
|
||||
|
||||
from tenants.admin import TenantRegistrationAdmin
|
||||
from django.contrib.admin.sites import AdminSite
|
||||
|
||||
admin = TenantRegistrationAdmin(TenantRegistration, AdminSite())
|
||||
tenant = admin._approve_registration(registration, self.admin_user)
|
||||
|
||||
# Проверяем тенант
|
||||
self.assertIsNotNone(tenant)
|
||||
self.assertTrue(tenant.is_active)
|
||||
|
||||
# Проверяем домен
|
||||
domain = Domain.objects.filter(tenant=tenant).first()
|
||||
self.assertIsNotNone(domain)
|
||||
|
||||
# Переключаемся на схему тенанта для проверки
|
||||
with schema_context('test_shop_complete'):
|
||||
# 1. Способы оплаты
|
||||
payment_methods_count = PaymentMethod.objects.count()
|
||||
self.assertEqual(payment_methods_count, 5, "Должно быть 5 способов оплаты")
|
||||
|
||||
# 2. Статусы заказов
|
||||
order_statuses_count = OrderStatus.objects.count()
|
||||
self.assertGreaterEqual(order_statuses_count, 3, "Должно быть минимум 3 статуса")
|
||||
|
||||
# 3. Системный клиент
|
||||
system_customer = Customer.objects.filter(is_system_customer=True).first()
|
||||
self.assertIsNotNone(system_customer, "Должен быть системный клиент")
|
||||
|
||||
# 4. Суперпользователь
|
||||
superuser = User.objects.filter(email=settings.TENANT_ADMIN_EMAIL).first()
|
||||
self.assertIsNotNone(superuser, "Должен быть суперпользователь")
|
||||
|
||||
# Проверяем заявку
|
||||
registration.refresh_from_db()
|
||||
self.assertEqual(registration.status, TenantRegistration.STATUS_APPROVED)
|
||||
|
||||
print("\n" + "=" * 70)
|
||||
print("✓ ПОЛНЫЙ ОНБОРДИНГ ТЕНАНТА ПРОШЁЛ УСПЕШНО")
|
||||
print("=" * 70)
|
||||
print(f"Тенант: {tenant.name}")
|
||||
print(f"Схема: {tenant.schema_name}")
|
||||
print(f"Домен: {domain.domain}")
|
||||
print(f"Способов оплаты: {payment_methods_count}")
|
||||
print(f"Статусов заказов: {order_statuses_count}")
|
||||
print(f"Системный клиент: ✓")
|
||||
print(f"Суперпользователь: ✓")
|
||||
print("=" * 70)
|
||||
Reference in New Issue
Block a user