我有一个非常复杂的 tests.py
文件。
实际上,测试类和方法是在运行时生成的 w/type
(考虑辅助文件中列出的数据)。我正在按照以下方式做事(更多代码见下文):
klass = type(name, (TestCase,), attrs)
setattr(current_module, name, klass)
仅供引用,使用通常的 django 测试运行程序,所有这些测试都会在执行 ./manage.py test myapp
时运行(感谢上面显示的 setattr
)。
我想做的是只运行这些测试的一部分,而不是手动列出它们的名字。
例如,我可以在类名或方法名中给每个测试“标签”,以便我可以对它们进行过滤。例如,我将执行:运行所有方法名称包含字符串“test_postgres_backend_”的测试
我尝试使用 django-nose
因为nose
的 -m
选项,它应该能够根据正则表达式选择测试,这是我的问题的理想解决方案。
不幸的是,这里是使用 django-nose 作为 django 测试运行器时发生的事情:
-
./manage.py test myapp
没有自动找到type
-生成测试类(与 django 测试运行器相反) - 都不是
./manage.py test -m ".*" myapp
也不./manage.py test myapp -m ".*"
找到任何测试,即使正常TestCase
类存在于文件中
所以:
- 除了尝试使用 django-nose
-m
之外,您还有其他解决我的一般问题的方法吗? ? - 与
django-nose
,你知道如何制作-m
吗?工作?
麦克韦
将以下内容添加到一个空的 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)
如果通过 django 测试运行器运行此输出(按 alphab 顺序):
F.F.F.F.F.F.FF.F.F.F.F..F.F.F.F.F.FF.F.F.F.F..F.F.F.F.F.FF.F.F.F.F..F.F.F.F.F.FF.F.F.F.F..F.F.F.F.F..
如果改为django_nose
测试运行器,./manage.py test myapp
上没有任何反应.
修复此问题后,我希望能够仅运行名称以 0
结尾的测试方法(或其他某种正则表达式过滤)
最佳答案
您遇到的问题是 Nose 通过查看记录在函数本身上的 name 来确定是否将方法包含到要运行的测试集中,而不是访问函数的属性。如果我将您的 passer
和 failer
重命名为 test_pass
和 test_fail
那么 Nose 就能够找到测试。因此,函数本身的命名方式必须与 -m
(或其默认值)相匹配。
这是给出预期结果的修改后的代码:
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
如果没有对 None
的最后两个赋值,Nose 会将这两个顶级函数视为模块级测试,并将在之外运行它们到类。
获得相同结果的另一种方法是在您的两个函数上定义 __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
在文件末尾:
# This prevents Nose from seeing them as tests after the loop is over.
passer = None
failer = None
Nose 在函数中寻找这些函数的存在,如果存在并设置为一个值被认为是真实的,它将将该函数作为测试用例。
控制方法选择的逻辑可以在 Nose 的 selector.py
文件中找到,位于 wantMethod
method。 :
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
我没有看到使用 -m
以您希望的方式仅运行一些测试的明确方法。问题在于 -m
平等地匹配文件、目录、模块、类和函数名称。如果您设置类似 -m0$
的内容,那么所有 我刚刚列出的各个部分必须与要选择的测试的正则表达式相匹配。 (Nose 不会将它们组合起来,然后在组合上进行匹配。)可以在命令行上单独列出测试,但这是正则表达式匹配的糟糕替代品。
关于python - 运行特定的 Django 测试(使用 django-nose?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29776211/