Можете ли вы полиморфировать тестовый пример python unittest?

Мне нужно проверить комбинацию двух параметров, каждый из которых имеет только несколько возможностей. Итак, я хочу иметь иерархию классов, в которой каждый подкласс имеет свой собственный фиксированный параметр A, а параметр B можно протестировать на основе этого общего параметра A. Я хочу полиморфировать методы тестирования в тестовом примере с точки зрения сдвига параметра A, так что мне не нужно переписывать методы тестирования для каждого тестируемого подкласса, но при этом могут быть вариации в тестах подклассов.

Однако я обнаружил, что если я объявлю атрибут в setUp(self). атрибут self.A не получает подкласса. Это означает, что все мои подклассы имеют одинаковое значение self.A из первого тестового примера (родительский класс). Также все мои testSomething(self) методы не являются виртуальными! Значение со следующей иерархией:

class baseTest(unittest.TestCase):
    def setUp(self):
        print('base setup')
        self.A = 100

    def testSomething(self):
        print('base test')
        # Do something with self.A

class subTest(baseTest):
    def setUp(self):
        print('sub setup')
        self.A = 999

    def testSomething(self):
        print('sub test')
        # Do something with self.A

EDIT: я поместил оба класса в один файл и полагался на unittest.main(), запущенный в if __name__ == "__main__"

Запуск этого файла дает мне:

base setup
base test
base setup
base test

Я думал, что все методы Python виртуальны, но в unittest это не так.

Что я должен делать?


person kakyo    schedule 21.01.2014    source источник


Ответы (3)


Не знаю, с чем вы столкнулись, но у меня это работает нормально...?

Используя ваш код, а затем добавив это:

a = baseTest()
b = subTest()

a.setUp()
a.testSomething()
b.setUp()
b.testSomething()

Вот мой вывод:

base setup
base test
sub setup
sub test
person Chris Arena    schedule 21.01.2014
comment
Я поместил оба класса в один файл и полагался на unittest.main(). - person kakyo; 22.01.2014
comment
Я подтверждаю, что при использовании Python 3.4.3 исходный код, окруженный import unittest и unittest.main(), работает просто отлично. Результат такой, как показано в этом ответе. - person Stein; 08.08.2015

ОБНОВЛЕНИЕ

Я реализовал план ниже, и он работает так, как ожидалось. Смотри ниже:

class baseTest(unittest.TestCase):
    def setUp(self):
        print('base setup')
        self.A = 100

    def testSomething(self):
        print('base test')
        self._DoTestSomething(self)

    def _DoTestSomething(self)
        # Do something with self.A

class subTest(baseTest):
    def setUp(self):
        print('sub setup')
        self.A = 999

    def _DoTestSomething(self)
        # Do something with self.A

СТАРЫЙ

Хорошо, теперь у меня есть план. Я могу написать реализации тестов в методах, отличных от testSomething(), которые должны быть виртуальными, а затем делегировать testSomething() этим виртуальным методам.

Я не проверял эту идею, но я думаю, что она должна работать.

person kakyo    schedule 21.01.2014
comment
почему голосование против? Я только что реализовал это, и это работает! - person kakyo; 22.01.2014
comment
Я проголосовал за это, потому что это не ответ на ваш вопрос. Это ты говоришь, что у тебя есть план попробовать что-то еще. - person Marcin; 28.01.2014
comment
Хорошо, у меня есть обновление с подробностями. Можете ли вы рассмотреть вопрос о голосовании за его резервное копирование? Спасибо. - person kakyo; 29.01.2014

testscenariosбиблиотека предназначена для использования написанных вами тестовых методов и некоторых сценариев данных для создания отдельные тестовые примеры для каждой комбинации (метод тестирования × сценарий).

Например:

import unittest
import testscenarios

from .. import system_under_test

class foo_TestCase(testscenarios.WithScenarios, unittest.TestCase):
    """ Test cases for `foo` function. """

    scenarios = [
            ('purple': {
                'wibble': "purple",
                'expected_count': 2,
                'expected_output': "Purple",
                }),
            ('orange': {
                'wibble': "orange",
                'expected_count': 3,
                'expected_output': "Orange",
                }),
            ('red': {
                'wibble': "red",
                'expected_count': 1,
                'expected_output': "Red",
                }),
            ]

    def test_has_expected_vowel_count(self):
        """ Should give the expected count of vowels. """
        vowel_count = system_under_test.foo(self.wibble)
        self.assertEqual(self.expected_count, vowel_count)

    def test_sets_expected_output(self):
        """ Should set the output to the expected value. """
        system_under_test.foo(self.wibble)
        self.assertEqual(self.expected_output, system_under_test.output)

Класс foo_TestCase при обнаружении тестов сгенерирует 6 тестов для средства выполнения тестов. У них будут имена, аннотированные именами сценариев, поэтому в итоговом отчете о тестировании каждый конкретный тестовый пример различается:

foo_TestCase.test_has_expected_vowel_count (purple)
foo_TestCase.test_has_expected_vowel_count (orange)
foo_TestCase.test_has_expected_vowel_count (red)
foo_TestCase.test_sets_expected_output (purple)
foo_TestCase.test_sets_expected_output (orange)
foo_TestCase.test_sets_expected_output (red)

Если вам это нужно, доступна большая гибкость — см. документацию testscenarios — но приведенное выше демонстрирует, как я использую его большую часть времени.

person bignose    schedule 27.06.2015