Я в настоящее время изучаю 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()
Лично мне больше нравится поколение тестов носа для подобных вещей. Тогда я бы написал это так:
# 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_')]
Почему бы просто не использовать псевдоним для класса, который вы хотите протестировать? Вы можете написать свой тестовый класс, ссылаясь на поддельный класс 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)
Если они соответствуют интерфейсу, который вы используете в тесте Suite, это должно работать нормально. Кроме того, вы можете легко протестировать столько реализаций, сколько захотите, просто добавьте их в список heaps
.
Я не думаю, что вышеприведенный шаблон ужасен, но множественное наследование - это, конечно, не идея.
Я думаю, причина, по которой вы не можете просто сделать TestHeap подклассом TestCase, в том, что он будет автоматически подхвачен и запущен как тест, не зная, что он должен быть подклассом.
Я обошел эту проблему двумя другими способами:
__test__ = False
для базового класса. (См. Testify)