简体   繁体   English

运行特定的Django测试(用django-nose?)

[英]Run specific Django tests (with django-nose?)

I am having a very complicated tests.py file. 我有一个非常复杂的tests.py文件。

Actually the tests classes and methods are generated at run time w/ type (to account for data listed in auxiliary files). 实际上,测试类和方法是在运行时生成的w / type (以考虑辅助文件中列出的数据)。 I am doing things in the following fashion (see below for more code): 我正在以下列方式做事(请参阅下面的更多代码):

klass = type(name, (TestCase,), attrs)
setattr(current_module, name, klass)

FYI, with the usual django test runner, all those tests get run when doing ./manage.py test myapp (thanks to the setattr shown above). 仅供参考,使用通常的django测试运行器,所有这些测试都会在执行./manage.py test myapp时运行(感谢上面显示的setattr )。

What I want to do is run only part of those tests, without listing their names by hand . 我想要做的只是运行部分测试,而不是手动列出他们的名字

For example, I could give each test "tags" in the class names or method names so that I could filter on them. 例如,我可以在类名或方法名中给每个测试“标签”,以便我可以对它们进行过滤。 For example I would then perform: run all tests which method name contains the string "test_postgres_backend_" 例如,我将执行: 运行所有测试哪个方法名称包含字符串“test_postgres_backend_”

I tried using django-nose because of nose 's -m option, which should be able to select tests based on regular expressions, an ideal solution to my problem. 我尝试使用django-nose因为nose-m选项,它应该能够选择基于正则表达式的测试,这是我的问题的理想解决方案。

Unfortunately, here is what is happening when using django-nose as the django test runner: 不幸的是,这里是使用django-nose作为django测试运行器时发生的事情:

  • ./manage.py test myapp is not finding automatically the type -generated test classes (contrarily to the django test runner) ./manage.py test myapp没有自动查找type生成的测试类(与django测试运行器相反)
  • neither ./manage.py test -m ".*" myapp nor ./manage.py test myapp -m ".*" find ANY test, even if normal TestCase classes are present in the file 既没有./manage.py test -m ".*" myapp也没有./manage.py test myapp -m ".*"找到任何测试, 即使文件中存在普通的TestCase

So: 所以:

  • Do you have another kind of solution to my general problem, rather than trying to use django-nose -m ? 你对我的一般问题有另一种解决方案,而不是尝试使用django-nose -m吗?
  • With django-nose , do you know how to make the -m work? 有了django-nose ,你知道如何让-m工作吗?

mcve MCVE

Add the following to an empty myapp/tests.py file: 将以下内容添加到空的myapp/tests.py文件中:

from django.test import TestCase
from sys import modules


current_module = modules[__name__]


def passer(self, *args, **kw):
    self.assertEqual(1, 1)


def failer(self, *args, **kw):
    self.assertEqual(1, 2)


# Create a hundred ...
for i in xrange(100):
    # ... of a stupid TestCase class that has 1 method that passes if `i` is
    # even and fails if `i` is odd
    klass_name = "Test_%s" % i
    if i % 2:  # Test passes if even
        klass_attrs = {
            'test_something_%s' % i: passer
        }
    else:      # Fail if odd
        klass_attrs = {
            'test_something_%s' % i: failer
        }
    klass = type(klass_name, (TestCase,), klass_attrs)

    # Set the class as "child" of the current module so that django test runner
    # finds it
    setattr(current_module, klass_name, klass)

If makes for this output run (in alphab order) by django test runnner: 如果通过django test runnner运行此输出(按字母顺序):
FFFFFFFF.FFFF.FFFFFFF.FFFF.FFFFFFF.FFFF.FFFFFFF.FFFF.FFFFF.

If you change to django_nose test runner, nothing happens on ./manage.py test myapp . 如果您更改为django_nose测试运行器,则./manage.py test myapp没有任何./manage.py test myapp

After fixing this, I would then like would be able to run only the test methods which name end with a 0 (or some other kind of regexable filtering) 修复此问题之后,我希望能够只运行名称以0结尾的测试方法 (或其他类型的可重用过滤)

The problem you ran into is that Nose determines whether or not to include a method into the set of tests to run by looking at the name recorded on the function itself, rather than the attribute that gives access to the function . 您遇到的问题是Nose通过查看函数本身记录名称来确定是否将方法包含到要运行的测试集中,而不是通过该属性来访问该函数 If I rename your passer and failer to test_pass and test_fail then Nose is able to find the tests. 如果我将你的passerpasser failer命名为test_passtest_fail那么Nose就能找到测试。 So the functions themselves have to be named in a way that will be matched by what is given to -m (or its default value). 因此,函数本身必须以与-m (或其默认值)给出的方式匹配。

Here's the modified code that gives the expected results: 这是修改后的代码,它给出了预期的结果:

from django.test import TestCase
from sys import modules

current_module = modules[__name__]

def test_pass(self, *args, **kw):
    self.assertEqual(1, 1)

def test_fail(self, *args, **kw):
    self.assertEqual(1, 2)

# Create a hundred ...
for i in xrange(100):
    # ... of a stupid TestCase class that has 1 method that passes if `i` is
    # even and fails if `i` is odd
    klass_name = "Test_%s" % i
    if i % 2:  # Test passes if even
        klass_attrs = {
            'test_something_%s' % i: test_pass
        }
    else:      # Fail if odd
        klass_attrs = {
            'test_something_%s' % i: test_fail
        }
    klass = type(klass_name, (TestCase,), klass_attrs)

    # Set the class as "child" of the current module so that django test runner
    # finds it
    setattr(current_module, klass_name, klass)

# This prevents Nose from seeing them as tests after the loop is over.
test_pass = None
test_fail = None

Without the final two assignments to None , Nose will consider the two top level functions to be module-level tests and will run them in addition to the tests in the classes. 如果没有对None的最后两个赋值,Nose会将两个顶级函数视为模块级测试,并且除了类中的测试之外还将运行它们。

Another way to get the same results would be to define __test__ on your two functions: 获得相同结果的另一种方法是在两个函数上定义__test__

def passer(self, *args, **kw):
    self.assertEqual(1, 1)
passer.__test__ = 1

def failer(self, *args, **kw):
    self.assertEqual(1, 2)
failer.__test__ = 1

And at the end of the file: 在文件的末尾:

# This prevents Nose from seeing them as tests after the loop is over.
passer = None
failer = None

Nose looks for the presence of these on functions and if present and set to a value is considered to be true, it will take the function as a test case. Nose在函数中查找这些函数的存在,如果存在并设置为一个值被认为是真的,它将把该函数作为测试用例。

The logic governing the selection of methods can be found in Nose's selector.py file, at the wantMethod method : 管理选择方法的逻辑可以在Nose的selector.py文件中找到,在wantMethod方法中

def wantMethod(self, method):
        """Is the method a test method?
        """
        try:
            method_name = method.__name__
        except AttributeError:
            # not a method
            return False
        if method_name.startswith('_'):
            # never collect 'private' methods
            return False
        declared = getattr(method, '__test__', None)
        if declared is not None:
            wanted = declared
        else:
            wanted = self.matches(method_name)
        plug_wants = self.plugins.wantMethod(method)
        if plug_wants is not None:
            wanted = plug_wants
        log.debug("wantMethod %s? %s", method, wanted)
        return wanted

I'm not seeing a clear way to use -m to run only some tests the way you want it. 我没有看到一个明确的方法来使用-m以你想要的方式运行一些测试。 The problem is that -m matches file, directorie, module, class, and function names equally. 问题是-m匹配文件,directorie,模块,类和函数名称。 If you set something like -m0$ then all the individual parts I just listed must match the regular expression for the test to be selected. 如果设置类似-m0$那么我刚刚列出的所有单个部分必须与要选择的测试的正则表达式匹配。 (Nose does not combine them and then match on the combination.) It is possible to list tests individually on the command line but this is a poor substitute to a regular expression match. (Nose不会将它们组合在一起,然后在组合上匹配。)可以在命令行上单独列出测试,但这不是正则表达式匹配的替代品。

In general you can run your specific test with something like this: 通常,您可以使用以下内容运行特定测试:

# assuming your tests are in core/tests.py
python manage.py test core.tests:CoreTestCase.my_specific_test

Have you tried this approach? 你尝试过这种方法吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM