6

我目前正在学习 python 为暑期的课程做准备,并通过实现不同类型的堆和基于优先级的数据结构开始。

我开始为该项目编写一个单元测试套件,但在创建一个只测试接口并且忽略实际实现的通用单元测试时遇到了困难。

我想知道是否有可能做这样的事情..

suite = HeapTestSuite(BinaryHeap())
suite.run()
suite = HeapTestSuite(BinomialHeap())
suite.run()

我目前正在做的只是感觉......错了(多重继承?ACK!)..

class TestHeap:

    def reset_heap(self):
        self.heap = None

    def test_insert(self):
        self.reset_heap()
        #test that insert doesnt throw an exception...
        for x in self.inseq:
            self.heap.insert(x)


    def test_delete(self):
        #assert we get the first value we put in
        self.reset_heap()
        self.heap.insert(5)
        self.assertEquals(5, self.heap.delete_min())

        #harder test. put in sequence in and check that it comes out right
        self.reset_heap()
        for x in self.inseq:
            self.heap.insert(x)

        for x in xrange(len(self.inseq)):
            val = self.heap.delete_min()
            self.assertEquals(val, x)

class BinaryHeapTest(TestHeap, unittest.TestCase):
    def setUp(self):
        self.inseq = range(99, -1, -1)
        self.heap = BinaryHeap()

    def reset_heap(self):
        self.heap = BinaryHeap()

class BinomialHeapTest(TestHeap, unittest.TestCase):
    def setUp(self):
        self.inseq = range(99, -1, -1)
        self.heap = BinomialHeap()

    def reset_heap(self):
        self.heap = BinomialHeap()


if __name__ == '__main__':
    unittest.main()
4

3 回答 3

4

我个人更喜欢这种事情的鼻子测试生成。然后我会这样写:

# They happen to all be simple callable factories, if they weren't you could put
# a function in here:
make_heaps = [BinaryHeap, BinomialHeap]

def test_heaps():
    for make_heap in make_heaps:
        for checker in checkers: # we'll set checkers later
            yield checker, make_heap

def check_insert(make_heap):
    heap = make_heap()
    for x in range(99, -1, -1):
        heap.insert(x)

# def check_delete_min etc.

checkers = [
    value
    for name, value in sorted(globals().items())
    if name.startswith('check_')]
于 2010-05-26T20:09:48.930 回答
2

为什么不直接为要测试的类使用别名呢?您可以编写引用假HeapImpl类的测试类,然后在每次测试运行之前为其分配特定的实现:

class TestHeap(unittest.TestCase):
    def setUp(self):
        self.heap = HeapImpl()
    #test cases go here

if __name__ == '__main__'
    suite = unittest.TestLoader().loadTestsFromTestCase(TestHeap)
    heaps = [BinaryHeap, BinomialHeap]
    for heap in heaps:
        HeapImpl = heap
        unittest.TextTestRunner().run(suite)

只要它们符合您在测试套件中使用的界面,这应该可以正常工作。此外,您可以轻松测试任意数量的实现,只需将它们添加到heaps列表中即可。

于 2010-05-26T18:45:05.710 回答
1

我不认为上面的模式很糟糕,但是多重继承肯定不是想法。

我猜你不能让 TestHeap 成为 TestCase 的子类的原因是因为它会自动被拾取并作为测试运行,而不知道它需要被子类化。

我已经通过其他两种方式解决了这个问题:

  1. 与其添加 test_ 函数,不如编写不会自动获取的方法,然后将 test() 添加到每个子类中。显然不理想。
  2. 将 unittest 重写为不吸,允许设置__test__ = False为基类的选项。(见作证
于 2010-05-26T17:30:45.540 回答