Python Unittest2 — избегайте включения тестового набора в discover()

#python #unit-testing #unittest2

#python #модульное тестирование #unittest2

Вопрос:

Я использую unittest2 on Python2.5 для обнаружения тестов с помощью unittest.TestLoader.discover , вот так:

 suite = unittest2.loader.TestLoader().discover(test_path)
unittest2.TextTestRunner(verbosity=2,
        resultclass=ColorTestResult).run(suite)
  

для некоторых test_path в основе моего проекта.

У меня есть базовый класс, который расширен и перегружен множеством других, но я хотел бы проверить, что эти производные не имеют регрессий. Давайте вызовем этот базовый класс A и его производные A1 , A2 и т.д.

Я хотел бы создать unittest2.TestCase базовый класс, который может быть перегружен для каждой из производных A . Другими словами, я хотел бы иметь иерархию, подобную этой:

 class A:
    pass

class A1(A):
    pass

class UT(unittest2.TestCase):
    target = A

class UT2(UT):
    target = A1
  

Теперь фокус в том, что я создаю A абстрактный класс, и UT практически все тестовые примеры, которые бы соответствовали UT2 , завершатся неудачей и т.д.

Мне кажется, что самым простым решением является то, чтобы unittest2 discover каким-то образом «пропускал» UT unittest2. Я думаю, это было бы возможно, поместив его в файл, отличный от одного соответствующего шаблона ‘test *.py’, хотя, похоже, это не так.

Существуют ли какие-либо решения для вышеупомянутого сценария, которые могли бы быть подходящими?

Я был бы благодарен за любые мысли и предложения.

Ответ №1:

Я предполагаю, что проблема в том, что UT2 наследуется от UT, поэтому модуль, в котором определен UT2, импортирует UT — и, следовательно, делает его доступным в пространстве имен модуля. Таким образом, даже если discovery не просматривает модуль, в котором определен UT, он все равно может найти тестовый набор в модуле UT2.

Это общая проблема с наличием базовых тестовых наборов, которые сами определяют тесты.

Есть несколько возможностей. Одним из них было бы предоставить UT через функцию, поэтому ваш модуль, содержащий UT2, импортирует функцию вместо UT напрямую:

 class UT2(get_base_class()):
    target = A1
  

Доступ к атрибутам в UT можно получить с помощью super().

Другим, возможно лучшим, решением было бы также сделать UT более абстрактным. Вы могли бы опустить цель в UT (поскольку, похоже, это не имеет смысла?) и вызвать программу установки SkipTest, если цели нет (или если целью является A).

Третьим решением было бы, чтобы UT не наследовал от TestCase, а использовал его как смешанный:

 class UT2(TestCase, UT):
     target = A1