Другая причина желания делать то, что делает OP, заключается в создании высокопараметризованного базового класса, который реализует большую часть набора базовых тестов, которые необходимо воспроизвести в нескольких средах / сценариях. То, что я описываю, это по сути создание параметризованного прибора, в виде pytest, с использованием unittest.
Предполагая, что вы (как и я) решили убежать как можно быстрее от любых решений, основанных на множественном наследовании, может возникнуть следующая проблема с использованием load_tests () для фильтрации вашего базового класса из загруженного набора:
В стандартном TestLoader load_tests называется после автоматическая загрузка из класса завершена. Так как:
* эта автозагрузка из класса будет пытаться создать экземпляры из вашего базового класса со стандартной подписью init (self, name) и
* вы можете захотеть, чтобы у этого базового класса была другая подпись ctor, или
* вы можете пропустить создание-затем-удаление экземпляров базового класса по какой-то другой причине
.. вы можете полностью запретить автоматическую загрузку тестовых экземпляров из базовых классов.
РЕДАКТИРОВАТЬ: Решение Вадима в этом другом потоке является более элегантным, лаконичным и независимым способом сделать это. Я реализовал «трюк с вложенными классами» и подтвердил, что он прекрасно работает с целью помешать TestLoader «найти» ваши базы TestCase.
Первоначально я сделал это, изменив TestLoader.loadTestsFromModule, чтобы просто пропустить любые классы TestCase, которые служат базовыми классами для любых других классов TestCase в модуле:
for name in dir(module):
obj = getattr(module, name)
# skip TestCase classes:
# 1. without any test methods defined
# 2. that are base classes
# (we don't allow instantiating TestCase base classes, which allows test designers
# to implement actual test methods in highly-parametrized base classes.)
if isinstance(obj, type) and issubclass(obj, unittest.TestCase) and \
self.getTestCaseNames(obj) and not isbase(obj, module):
loaded_suite = self.loadTestsFromTestCase(obj)
# ignore empty suites
if loaded_suite.countTestCases():
tests.append(loaded_suite)
где:
def isbase(cls, module):
'''Returns True if cls is base class to any classes in module, else False.'''
for name in dir(module):
obj = getattr(module, name)
if obj is not cls and isinstance(obj, type) and issubclass(obj, cls):
return True
return False
Параметризация, о которой я говорил выше, реализуется с помощью того, чтобы каждый дочерний класс определял детали своего прибора (параметры) и передавал их в базовый класс TestCase ctor, чтобы все его общие методы impl ("fixturey" setUp * / tearDown * / cleanup * и сами методы тестирования) имеют всю информацию, которая определяет теперь очень специфическое приспособление, с которым должен работать этот дочерний класс TestCase.
Для меня это было временное решение для быстрой реализации некоторых параметризованных приборов в unittest, так как я планирую перенести тесты моей команды на pytest как можно скорее.