6

这是我之前的问题的后续。

在上一个问题中,探索了在整个函数系列中实现基本相同的测试的方法,确保测试不会在第一个失败的函数处停止。

我首选的解决方案使用元类将测试动态插入到 unittest.TestCase 中。不幸的是,nose 没有选择这个,因为nose 静态扫描测​​试用例。

我如何才能发现并运行这样的 TestCase?请参阅此处以获取相关 TestCase 的示例。

4

3 回答 3

8

鼻子有一个“测试生成器”功能来处理这样的事情。您编写一个生成器函数,该函数生成您希望它运行的每个“测试用例”函数及其参数。按照您之前的示例,这可以在单独的测试中检查每个功能:

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)
于 2009-03-24T07:19:15.410 回答
2

Nose 不会静态扫描测​​试,因此您可以使用元类魔法来制作 Nose 找到的测试。

困难的部分是标准元类技术没有正确设置 func_name 属性,这是 Nose 在检查类上的方法是否是测试时所寻找的。

这是一个简单的元类。它查看 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并将具有greeter、和作为其方法。当我在这个文件上运行时,输出如下:greeter_no_docstringtest_1test_2nosetests

$ 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)where funcis made 作为默认参数的原因。在 上使用闭包会更自然value,但这似乎不起作用。

于 2012-11-27T08:00:07.497 回答
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 .."}
)

这应该在鼻子尝试导入您的 test_module 时创建,以便它应该工作。

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

于 2008-12-14T14:54:30.443 回答