关于python:来自函数和值字典的unittest

Unittest from a dictionary of functions and values

我刚接触过Python中的unittests模块,所以答案可能很明显。我有一堆属性,我想检查一下我是否存储在字典中:

1
2
3
4
5
petersen_prop = {
   "n_vertex" : 10,
   "n_edge"   : 15,
    ...
}

每个"键"都是一个函数的名称,值是我希望UnitTests验证的目标。有效的是相当冗长的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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,我不得不反复复制和粘贴相同的代码块。是否有一种以编程方式添加这些代码块的方法,以便单元测试能够按预期工作?为了清楚起见,我希望输入是上面的字典,输出是一个工作相同的UnitTest对象。


您可以迭代petersen_prop字典中的键,并根据键名调用正确的函数。

1
2
3
4
5
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])

或者,如果没有将所有函数名导入到测试模块的命名空间中,则如下所示:

1
2
3
4
5
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_propdict中:

1
2
3
4
5
6
7
8
9
10
11
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])

编辑:

下面是使用元类为dict中的每个项添加唯一测试的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
======================================================================
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


python没有从函数内部获取函数名的功能。你所能做的就是test_n_vertex.__name__,它将把'test_n_vertex'作为一个字符串。您可以使用基本的字符串函数来做您需要做的事情。但是您所期望的确切功能并不存在。

有关详细信息,请参阅此处从该函数内确定函数名(不使用回溯)