从函数和值字典中进行单元测试

0 投票
2 回答
3960 浏览
提问于 2025-04-18 17:00

我刚接触Python里的unittests模块,所以可能有些问题很明显。我有一堆属性想要检查,这些属性存储在一个字典里:

petersen_prop = {
    "n_vertex" : 10,
    "n_edge"   : 15,
    ...
}

字典里的每个“键”都是一个函数的名字,而对应的值是我希望单元测试验证的目标。现在我用的代码比较冗长:

import unittest
class PetersenGraph(unittest.TestCase):

    def setUp(self):
        # Create the graph here (not important to the question)
        self.args = args
        self.adj = adj

    def test_n_vertex(self):
        self.assertTrue(n_vertex(self.adj,**self.args) == 
                        petersen_prop["n_vertex"])

    def test_n_edge(self):
        self.assertTrue(n_edge(self.adj,**self.args) == 
                        petersen_prop["n_edge"])

    # ..... hundreds of similar looking code blocks


unittest.main(verbosity=2)

我感觉这样做有点违反了DRY原则,因为我需要一遍又一遍地复制粘贴同样的代码块。有没有办法可以程序化地添加这些代码块,让单元测试正常工作?简单来说,我希望输入是上面的字典,输出是一个功能相同的单元测试对象。

2 个回答

0

在Python中,想要在一个函数内部获取这个函数的名字,其实是没有直接的功能的。不过,你可以用 test_n_vertex.__name__ 这个方式来获取函数的名字,它会返回 'test_n_vertex' 这个字符串。你可以利用一些基本的字符串操作来完成你需要的事情。但是,想要的那种功能是不存在的。

想了解更多信息,可以查看这里: 在函数内部获取函数名(不使用traceback)

1

你可以遍历 petersen_prop 字典里的键,然后根据键的名字调用相应的函数。

def test_n_props(self):
    for cur_prop in petersen_prop:
        func = globals()[cur_prop]
        self.assertTrue(func(self.adj,**self.args) == 
                        petersen_prop[cur_prop])

或者,如果你不把所有的函数名都导入到测试模块的命名空间里,可以这样做:

def test_n_props(self):
    for cur_prop in petersen_prop:
        func = getattr(myfuncs, cur_prop)
        self.assertTrue(func(self.adj,**self.args) == 
                        petersen_prop[cur_prop])

你也可以把实际的函数对象存储在 petersen_prop 字典里:

petersen_prop = {
    "n_vertex" : (10, n_vertex)
    "n_edge"   : (15, n_edge)
    ...
}

def test_n_props(self):
    for cur_prop in petersen_prop:
        func = petersen_map[cur_prop][1]
        self.assertTrue(func(self.adj,**self.args) == 
                        petersen_prop[cur_prop][0])

编辑:

这里有一种方法可以为字典中的每个项目添加一个独特的测试,使用元类来实现:

class TestMaker(type):
    def __new__(cls, clsname, bases, dct):
        # Add a method to the class' __dict__ for every key in
        # the petersen_prop dict.
        for prop in petersen_prop:
            dct['test_{}'.format(prop)] = cls.make_test(prop)

        return super(TestMaker, cls).__new__(cls, clsname, bases, dct)

    @staticmethod
    def make_test(prop):
        # test_wrap is the method body that will be used for each
        # test
        def test_wrap(self):
            func = getattr(myfuncs, prop)
            self.assertTrue(func(self.adj, **self.args) ==
                    petersen_prop[prop])
        return test_wrap

class PetersenGraph(unittest.TestCase):
   __metaclass__ = TestMaker

当你运行这个时,每个项目都会得到一个单独的测试用例。例如,在我的测试代码中,每个测试都失败了:

======================================================================
FAIL: test_n_edge (__main__.PetersenGraph)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "un.py", line 26, in test_wrap
    petersen_prop[prop])
AssertionError: False is not true

======================================================================
FAIL: test_n_vertex (__main__.PetersenGraph)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "un.py", line 26, in test_wrap
    petersen_prop[prop])
AssertionError: False is not true

撰写回答