Journal [Django] Détecter une migration manquante via les tests unitaires

Posté par  (site web personnel) . Licence CC By‑SA.
Étiquettes :
8
28
fév.
2025

Django a un chouette système de migrations pour répercuter sur la db les changements effectués sur les modèles.

Mais des fois, oups, on oublie de déclarer les nouvelles migrations.

Avec ce simple test case, vous pouvez détecter le problème via les tests unitaires et ainsi vous assurez que votre CI/CD ne déploit jamais du code où les modèles ne sont plus synchronisés par rapport à la db.

#  DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 
#                     Version 2, December 2004 
#
#  Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> 
#
#  Everyone is permitted to copy and distribute verbatim or modified 
#  copies of this license document, and changing it is allowed as long 
#  as the name is changed. 
#
#             DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 
#    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 
#
#   0. You just DO WHAT THE FUCK YOU WANT TO.

from django.core.management import call_command
from django.test import TestCase


class MissingMigrationTestCase(TestCase):
    def test_is_a_migration_missing(self):
        try:
            call_command("makemigrations", "--check", "--verbosity=0")
        except SystemExit:
            self.fail("You have updated the models but forget to create a migration.")

Démo :

$ ./manage.py test tests.windfit.models.test_missing_migration.MissingMigrationTestCase.test_is_a_migration_missing
Found 1 test(s).
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
F
======================================================================
FAIL: test_is_a_migration_missing (tests.windfit.models.test_missing_migration.MissingMigrationTestCase.test_is_a_migration_missing)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/jtremesay/projects/webfit/tests/windfit/models/test_missing_migration.py", line 8, in test_is_a_migration_missing
    call_command("makemigrations", "--check", "--verbosity=0")
    ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jtremesay/projects/webfit/.direnv/python-3.13/lib/python3.13/site-packages/django/core/management/__init__.py", line 194, in call_command
    return command.execute(*args, **defaults)
           ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
  File "/home/jtremesay/projects/webfit/.direnv/python-3.13/lib/python3.13/site-packages/django/core/management/base.py", line 459, in execute
    output = self.handle(*args, **options)
  File "/home/jtremesay/projects/webfit/.direnv/python-3.13/lib/python3.13/site-packages/django/core/management/base.py", line 107, in wrapper
    res = handle_func(*args, **kwargs)
  File "/home/jtremesay/projects/webfit/.direnv/python-3.13/lib/python3.13/site-packages/django/core/management/commands/makemigrations.py", line 261, in handle
    sys.exit(1)
    ~~~~~~~~^^^
SystemExit: 1

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/jtremesay/projects/webfit/tests/windfit/models/test_missing_migration.py", line 10, in test_is_a_migration_missing
    self.fail("You have updated the models but forget to create a migration.")
    ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: You have updated the models but forget to create a migration.

----------------------------------------------------------------------
Ran 1 test in 0.246s

FAILED (failures=1)
Destroying test database for alias 'default'...
  • # Pour continuer dans cette direction

    Posté par  . Évalué à 2 (+2/-0).

    Quelques autres idées pour éviter de casser un site django en prodution avec des migrations:

    Il est possible de tester les migrations manuelles avec django-test-migrations. Cela permet de vérifier que les modifications des données effectuées dans la migration fonctionnent bien dans tous les cas. C’est aussi utile pour vérifier les migrations inverses. Le repo n’a pas été mis à jour depuis longtemps mais cela fonctionne encore bien.

    Il est aussi facile de vérifier que l’on ne crée pas de migration incompatible avec la version en production. Très utile quand on fait des rolling updates:

    python manage.py test --keepdb
    git checkout [commit déployé en prod]
    python manage.py test --keepdb

Envoyer un commentaire

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.