2008-12-07 62 views
6

这是我的previous question的后续行动。如何获取鼻子来发现动态生成的测试用例?

在前面的问题中,我们探索了一些方法来实现对整个函数族进行基本相同的测试,以确保测试不会停在第一个失败的函数上。

我的首选解决方案使用元类来动态地将测试插入unittest.TestCase。不幸的是,由于鼻子静态扫描测​​试用例,所以鼻子不会选择它。

如何获得鼻子来发现并运行这样的TestCase?有关TestCase的示例,请参阅here

+0

你试过我的解决方案吗?它不是基于任何魔法,所产生的套件应该是可以发现的。 – muhuk 2008-12-07 15:50:19

回答

7

鼻子有这样的东西“测试发电机”功能。你编写一个生成器函数,生成你想运行它的每个“测试用例”函数以及它的参数。继以前的例子,这可以检查每个功能在一个单独的测试:

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) 
0

你可以尝试生成测试用例类与类型()

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 .."} 
) 

当鼻子试图导入test_module所以它应该工作这应该被创建。

这种方法的优点是可以动态创建多个测试组合。

2

鼻子不扫描测试静态,这样你就可以使用元类魔法使测试,鼻子找到。

难题在于标准元类技术不能正确设置func_name属性,这是鼻子在检查类中的方法是否为测试时寻找的内容。

这是一个简单的元类。它通过func dict来查看,并为它找到的每个方法添加一个新方法,声明它找到的方法有一个文档字符串。这些新的合成方法被命名为"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,将有greetergreeter_no_docstringtest_1test_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标准,作为鼻子测试套件的一部分。

此外,我有很多麻烦得到适当的封闭与新的工作。函数,这就是为什么此代码使用m(self, func)其中func被设置为默认参数。使用value以上的封闭会更自然,但这似乎不起作用。