如何让nose发现动态生成的测试用例?
3 个回答
1
你可以试着用type()来生成测试用例的类。
class UnderTest_MixIn(object):
def f1(self, i):
return i + 1
def f2(self, i):
return i + 2
SomeDynamicTestcase = type(
"SomeDynamicTestcase",
(UnderTest_MixIn, unittest.TestCase),
{"even_more_dynamic":"attributes .."}
)
# or even:
name = 'SomeDynamicTestcase'
globals()[name] = type(
name,
(UnderTest_MixIn, unittest.TestCase),
{"even_more_dynamic":"attributes .."}
)
这个类应该在nose尝试导入你的测试模块时创建,所以应该没问题。
这种方法的好处是,你可以动态地创建很多不同组合的测试。
2
Nose这个工具不会静态地扫描测试,所以你可以用一些特别的技巧来让Nose找到你的测试。
难点在于,普通的技巧并不能正确设置一个叫做func_name的属性,而Nose正是通过这个属性来判断你类里的方法是否是测试。
下面是一个简单的元类。它会查看函数字典,并为每个找到的方法添加一个新方法,确保这个方法有文档字符串。这些新方法的名字会被命名为"test_%d" %i
。
import new
from inspect import isfunction, getdoc
class Meta(type):
def __new__(cls, name, bases, dct):
newdct = dct.copy()
for i, (k, v) in enumerate(filter(lambda e: isfunction(e[1]), dct.items())):
def m(self, func):
assert getdoc(func) is not None
fname = 'test_%d' % i
newdct[fname] = new.function(m.func_code, globals(), fname,
(v,), m.func_closure)
return super(Meta, cls).__new__(cls, 'Test_'+name, bases, newdct)
现在,我们来创建一个使用这个元类的新类。
class Foo(object):
__metaclass__ = Meta
def greeter(self):
"sdf"
print 'Hello World'
def greeter_no_docstring(self):
pass
在运行时,Foo
实际上会被命名为Test_Foo
,并且会有greeter
、greeter_no_docstring
、test_1
和test_2
这些方法。当我在这个文件上运行nosetests
时,输出结果是:
$ nosetests -v test.py
test.Test_Foo.test_0 ... FAIL
test.Test_Foo.test_1 ... ok
======================================================================
FAIL: test.Test_Foo.test_0
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Library/Frameworks/EPD64.framework/Versions/7.3/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
self.test(*self.arg)
File "/Users/rmcgibbo/Desktop/test.py", line 10, in m
assert getdoc(func) is not None
AssertionError
----------------------------------------------------------------------
Ran 2 tests in 0.002s
FAILED (failures=1)
这个元类本身并不是特别有用,但如果你把Meta
用作一种功能性元类(也就是说,把一个类作为参数传入,然后返回一个新类,这个新类的名字改了,以便Nose能找到它),那它就有用了。我用这种方法来自动测试文档字符串是否符合Numpy标准,作为Nose测试套件的一部分。
另外,我在使用new.function时遇到了很多麻烦,这就是为什么这段代码使用m(self, func)
,其中func
被设为默认参数。用value
来做闭包会更自然,但似乎不太管用。
8
Nose有一个叫“测试生成器”的功能,可以用来处理这种情况。你需要写一个生成器函数,这个函数会逐个返回你想要运行的“测试用例”函数,以及它的参数。根据你之前的例子,这样可以在不同的测试中检查每一个函数:
import unittest
import numpy
from somewhere import the_functions
def test_matrix_functions():
for function in the_functions:
yield check_matrix_function, function
def check_matrix_function(function)
matrix1 = numpy.ones((5,10))
matrix2 = numpy.identity(5)
output = function(matrix1, matrix2)
assert matrix1.shape == output.shape, \
"%s produces output of the wrong shape" % str(function)