Как я могу вызвать пользовательскую команду Django manage.py прямо из тестового драйвера? - PullRequest
154 голосов
/ 25 мая 2009

Я хочу написать модульный тест для команды Django manage.py, которая выполняет внутреннюю операцию над таблицей базы данных. Как бы я вызвал команду управления прямо из кода?

Я не хочу выполнять команду на оболочке операционной системы из tests.py, потому что я не могу использовать тестовую среду, настроенную с использованием теста manage.py (тестовая база данных, тестовая фиктивная электронная почта и т. Д.) )

Ответы [ 5 ]

278 голосов
/ 25 мая 2009

Лучший способ проверить такие вещи - извлечь необходимую функциональность из самой команды в автономную функцию или класс. Это помогает абстрагироваться от «материала для выполнения команд» и написать тест без дополнительных требований.

Но если вы по какой-то причине не можете отделить команду логической формы, вы можете вызвать ее из любого кода, используя call_command метод, подобный этому:

from django.core.management import call_command

call_command('my_command', 'foo', bar='baz')
21 голосов
/ 02 августа 2011

Вместо того, чтобы делать трюк call_command, вы можете запустить свою задачу, выполнив:

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)
16 голосов
/ 26 октября 2013

следующий код:

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

... соответствует следующим командам, набранным в терминале:

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

См. запуск команд управления из django docs .

10 голосов
/ 29 сентября 2016

В документации Django для call_command не упоминается, что out необходимо перенаправить на sys.stdout. Пример кода должен выглядеть следующим образом:

from django.core.management import call_command
from django.test import TestCase
from django.utils.six import StringIO
import sys

class ClosepollTest(TestCase):
    def test_command_output(self):
        out = StringIO()
        sys.stdout = out
        call_command('closepoll', stdout=out)
        self.assertIn('Expected output', out.getvalue())
1 голос
/ 21 января 2013

Опираясь на ответ Нейта, у меня есть это:

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

Использование:

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

Преимущество здесь в том, что если вы использовали дополнительные опции и OptParse, это поможет вам. Он не совсем совершенен - ​​и пока не передает результаты - но будет использовать тестовую базу данных. Затем вы можете проверить эффекты базы данных.

Я уверен, что использование макетного модуля Micheal Foords, а также переподключение стандартного вывода на время теста означало бы, что вы также можете получить больше от этой техники - проверить выход, условия выхода и т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...