24

是否可以将命令行参数传递给 Django 的manage.py脚本,特别是用于单元测试?即如果我做类似的事情

manage.py test myapp -a do_this

我可以接收单元测试功能中do_this的值吗?setUp

PS @Martin 询问在测试中使用命令行参数的理由:

  • 一些广泛的测试需要花费大量时间,并且不需要在每次提交之前运行。我想让它们成为可选的。

  • 我的测试用例打印的偶尔调试消息应该是可选的

  • 有时我只是想让测试变得疯狂并尝试更多的数据排列。

使用命令行选项,以上所有内容都会非常方便。偶尔测试可能会更广泛或更冗长,否则会很快。

4

5 回答 5

10

我自己也遇到了这个问题,想避免在命令行设置环境变量。环境变量确实有效,但很难跟踪哪些变量会产生影响,并且没有错误消息让您知道是否输入了错误。

为了解决这个问题,我曾经argparse将额外的参数提取到命令行参数中。例如,我的manage.py文件现在看起来像这样:

#!/usr/bin/env python
import os
import sys
import argparse


if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings")

    argv = sys.argv
    cmd = argv[1] if len(argv) > 1 else None
    if cmd in ['test']:  # limit the extra arguments to certain commands
        parser = argparse.ArgumentParser(add_help=False)
        parser.add_argument('--foo', default='bar')
        args, argv = parser.parse_known_args(argv)
        # We can save the argument as an environmental variable, in
        # which case it's to retrieve from within `project.settings`,
        os.environ['FOO'] = args.foo
        # or we can save the variable to settings directly if it
        # won't otherwise be overridden.
        from django.conf import settings
        settings.foo = args.foo

    from django.core.management import execute_from_command_line

    # parse_known_args strips the extra arguments from argv,
    # so we can safely pass it to Django.
    execute_from_command_line(argv)

argparse是一个非常好的库,有很多功能。Python 文档中有一个很好的教程

于 2017-05-09T19:56:57.780 回答
9

我在我的项目中使用环境变量解决方法(仅适用于类 unix 的 shell)

berry$ myvar=myval ./manage.py test 

在您的模块中使用

os.environ.get('myvar')
于 2016-03-06T00:41:38.537 回答
4

作为替代方法,manage.py test -a do_this您可以使用特定的设置文件

manage.py --settings=project.test_settings test

并在此文件中定义您想要的任何内容。

# test_setting.py
SPECIFIC_OPTION = "test"

# tests.py
from django.conf import settings
...
def setUp(self):
    if settings.SPECIFIC_OPTION:
        ....

如果您需要真正的动态选项,也许您可​​以使用sys.argvin test_settings.py,但它是一个非常肮脏的 hack。

于 2015-01-30T08:07:40.047 回答
4

Django 允许从 testrunner 类添加自定义命令行选项。您可以创建默认 testrunner 类的子类并添加您自己的选项,然后让 django 使用您的自定义 testrunner,如下所示。

例如,在您的 Django 项目目录中创建一个 testrunner.py,其中包含:

from django.test.runner import DiscoverRunner

class TestRunner(DiscoverRunner):
    def __init__(self, option=None, **kwargs):
        super().__init__(**kwargs)

        print("Passed option: {}".format(option))

    @classmethod
    def add_arguments(cls, parser):
        DiscoverRunner.add_arguments(parser)

        parser.add_argument('-o', '--option', help='Example option')

这是一个从默认运行程序派生的测试运行程序(因此它的工作方式与默认运行程序一样),只是它告诉 django 添加一个额外的命令行选项(在add_arguments()类方法中)并在构造函数中处理这个额外选项的值。要使用这个新的跑步者运行,请按如下方式传递其名称:

./manage.py test --testrunner=testrunner.TestRunner -o foo

当然,您可以将此类放在其他任何地方,只要您在命令行上将完整的导入名称传递给它。

请注意,您必须使用--testrunner=foo,不能使用两个单独的参数 ( --testrunner foo),因为这样额外的参数不起作用。正在等待修复:https ://github.com/django/django/pull/10307

此示例仅打印选项值,但您需要以某种方式将其传递给您的测试用例。我找不到有关如何将选项传递给 unittest 测试用例的任何快速信息,但您可能只使用全局(模块级别)变量或类变量(这不是那么可重入和优雅,但很容易和作品)。

于 2018-08-17T18:25:12.950 回答
1

跟进@Matthijs 的回答,您可以扩展setup_test_environment类似于DiscoveryRunner处理debug-mode的方法。它通过导入来更改settings.DEBUG可以在测试中使用的值django.conf.settings。但您也可以添加自己的设置:

from django.test.runner import DiscoverRunner

class TestRunner(DiscoverRunner):
    def __init__(self, option=None, **kwargs):
        super().__init__(**kwargs)

        print("Passed option: {}".format(option))
        self.option = option

    @classmethod
    def add_arguments(cls, parser):
        DiscoverRunner.add_arguments(parser)

        parser.add_argument('-o', '--option', help='Example option')

    def setup_test_environment(self, **kwargs):
        super(TestRunner, self).setup_test_environment(**kwargs)
        settings.TEST_SETTINGS = {
            'option': self.option,
        }

在测试中,您可以通过设置简单地访问该选项

from django.test import TestCase
from django.conf import settings


class MyTestCase(TestCase):

    def test_something(self):
        if settings.TEST_SETTINGS['option']:
            print("Do stuff")
于 2020-05-27T10:50:23.023 回答