我想为Django manage.py命令编写单元测试,该命令对数据库表执行后端操作。我如何直接从代码中调用管理命令?
我不想从tests.py在操作系统的shell上执行命令,因为我无法使用manage.py test设置的测试环境(测试数据库,测试虚拟电子邮件发件箱等等... )
答案 0 :(得分:277)
测试此类事物的最佳方法 - 从命令本身提取所需的功能到独立的功能或类。它有助于从“命令执行东西”中抽象出来并编写测试而无需额外的要求。
但是如果你由于某种原因无法解耦逻辑形式命令,你可以使用call_command方法从任何代码中调用它:
from django.core.management import call_command
call_command('my_command', 'foo', bar='baz')
答案 1 :(得分:21)
您可以通过执行以下操作来运行您的任务:
,而不是执行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)
答案 2 :(得分:16)
以下代码:
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
答案 3 :(得分:10)
Django documentation on the 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())
答案 4 :(得分:1)
根据Nate的回答,我有这个:
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模拟模块并在测试期间重新连接stdout意味着你也可以从这项技术中获得更多 - 测试输出,退出条件等。