Comment puis-je appeler une commande personnalisée de Django manage.py directement depuis un pilote de test?

Je veux écrire un test unitaire pour une commande Django manage.py qui effectue une opération backend sur une table de firebase database. Comment puis-je invoquer la commande de gestion directement à partir du code?

Je ne veux pas exécuter la commande sur le shell du système d’exploitation à partir de tests.py car je ne peux pas utiliser l’environnement de test configuré à l’aide du test manage.py (base de test, boîte aux lettres de test, etc.)

Le meilleur moyen de tester de telles choses – extraire les fonctionnalités nécessaires de la commande elle-même vers une fonction ou une classe autonome. Cela aide à extraire des “trucs d’exécution de commandes” et à écrire des tests sans exigences supplémentaires.

Mais si vous ne parvenez pas à découpler la commande de la forme logique, vous pouvez l’appeler depuis n’importe quel code en utilisant la méthode call_command comme ceci:

from django.core.management import call_command call_command('my_command', 'foo', bar='baz') 

Plutôt que de faire le tour call_command, vous pouvez exécuter votre tâche en procédant comme suit:

 from myapp.management.commands import my_management_task cmd = my_management_task.Command() opts = {} # kwargs for your command -- lets you override stuff for testing... cmd.handle_noargs(**opts) 

le code suivant:

 from django.core.management import call_command call_command('collectstatic', verbosity=3, interactive=False) call_command('migrate', 'myapp', verbosity=3, interactive=False) 

… est égal aux commandes suivantes saisies dans le terminal:

 $ ./manage.py collectstatic --noinput -v 3 $ ./manage.py migrate myapp --noinput -v 3 

Voir l’ exécution des commandes de gestion à partir de django docs .

La documentation de Django sur call_command ne parvient pas à mentionner que la out doit être redirigée vers sys.stdout . L’exemple de code doit se lire comme suit:

 from django.core.management import call_command from django.test import TestCase from django.utils.six import SsortingngIO import sys class ClosepollTest(TestCase): def test_command_output(self): out = SsortingngIO() sys.stdout = out call_command('closepoll', stdout=out) self.assertIn('Expected output', out.getvalue()) 

En me basant sur la réponse de Nate, j’ai ceci:

 def make_test_wrapper_for(command_module): def _run_cmd_with(*args): """Run the possibly_add_alert command with the supplied arguments""" cmd = command_module.Command() (opts, args) = OptionParser(option_list=cmd.option_list).parse_args(list(args)) cmd.handle(*args, **vars(opts)) return _run_cmd_with 

Usage:

 from myapp.management import mycommand cmd_runner = make_test_wrapper_for(mycommand) cmd_runner("foo", "bar") 

L’avantage étant que si vous avez utilisé des options supplémentaires et OptParse, cela vous permettra de régler le problème. Ce n’est pas tout à fait parfait – et il ne produit pas encore de résultats – mais il utilisera la firebase database de test. Vous pouvez ensuite tester les effets de firebase database.

Je suis sûr que l’utilisation du module de simulation de Micheal Foords et la refermeture de la sortie standard pendant la durée d’un test signifieraient que vous pourriez également tirer parti de cette technique – testez la sortie, les conditions de sortie, etc.