这是我previous question的后续行动。
在上一个问题中,探索了一些方法来实现对整个函数族基本上相同的测试,确保测试不会在第一个失败的函数处停止。
我首选的解决方案是使用元类将测试动态插入unittest.TestCase。不幸的是,鼻子不会选择这个,因为鼻子静态扫描测试用例。
如何让鼻子发现并运行这样的TestCase?有关TestCase的示例,请参阅here。
答案 0 :(得分:7)
Nose有这样的东西的“测试生成器”功能。您编写了一个生成器函数,该函数生成您希望它运行的每个“测试用例”函数及其args。按照上一个示例,这可以在单独的测试中检查每个函数:
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)
答案 1 :(得分:2)
Nose不会静态扫描测试,因此可以使用元类魔法来进行Nose发现的测试。
困难的部分是标准的元类技术没有正确设置func_name属性,这就是Nose在检查你的类上的方法是否是测试时所寻找的。 p>
这是一个简单的元类。它查看了func dict并为它找到的每个方法添加了一个新方法,断言它找到的方法有一个docstring。这些新的合成方法的名称为"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
作为一个正确的元类,而是使用更多的函数元类(即将一个类作为参数并返回一个新类) ,一个重命名,以便鼻子会找到它),然后它 有用。我已经使用这种方法自动测试文档字符串是否符合Numpy标准作为鼻子测试套件的一部分。
此外,我在使用new.function进行正确的闭包时遇到了很多麻烦,这就是为什么此代码使用m(self, func)
,其中func
是默认参数。使用value
上的闭包更自然,但这似乎不起作用。
答案 2 :(得分:0)
您可以尝试使用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尝试导入test_module时创建,以便它可以正常工作。
这种方法的优点是您可以动态创建多种测试组合。