Какие существуют подходы к тестированию миграций в Django

«Какие существуют подходы к тестированию миграций в Django» — вопрос из категории Тестирование, который задают на 10% собеседований Python Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Тестирование миграций в Django — ключевая практика для обеспечения стабильности схемы БД. Основные подходы:

  1. Проверка генерации миграций

    Этот тест проверяет, что для текущего состояния моделей не требуется создавать новые файлы миграций. Идеально подходит для CI/CD пайплайнов.

    from django.core.management import call_command
    from django.test import TestCase
    
    class MigrationGenerationTest(TestCase):
        def test_no_missing_migrations(self):
            # Команда завершится с ошибкой, если миграции не созданы
            call_command('makemigrations', check=True)
  2. Проверка применения и отката миграций

    Тест гарантирует, что все миграции в приложении могут быть успешно применены (forward) и отменены (backward), не вызывая ошибок.

    from django.core.management import call_command
    from django.test import TestCase
    
    class MigrationApplicationTest(TestCase):
        def test_migrations_can_be_applied_and_rolled_back(self):
            # Применяем все миграции для приложения 'my_app'
            call_command('migrate', 'my_app', verbosity=0)
            # Откатываем все миграции для 'my_app' до начального состояния
            call_command('migrate', 'my_app', 'zero', verbosity=0)
  3. Тестирование миграций данных (Data Migrations)

    Если миграция изменяет данные, необходимо проверить корректность этих изменений. Тест должен создать данные в состоянии до миграции, применить миграцию и проверить, что данные были преобразованы правильно.

    Для этого часто используют сторонние библиотеки, например django-test-migrations, которая упрощает процесс.

    Пример с django-test-migrations:

    # tests/test_migrations.py
    from django_test_migrations.contrib.unittest_case import MigratorTestCase
    
    class TestUserDataMigration(MigratorTestCase):
        # Указываем состояние БД до миграции, которую хотим протестировать
        migrate_from = ('users', '0005_add_user_profile')
        # Указываем саму миграцию
        migrate_to = ('users', '0006_populate_user_full_name')
    
        def prepare(self):
            # Создаем данные в старом формате
            User = self.old_state.apps.get_model('users', 'User')
            User.objects.create(first_name='John', last_name='Doe')
    
        def test_data_is_migrated(self):
            # Проверяем данные после применения миграции
            User = self.new_state.apps.get_model('users', 'User')
            user = User.objects.get(id=1)
            self.assertEqual(user.full_name, 'John Doe')