想要执行OP正在执行的操作的另一个原因是创建一个高度参数化的基类,该基类实现许多需要在几种环境/场景中重现的核心测试集。 我要描述的实际上是使用unittest创建一个参数化的夹具,一个pytest。
假设您(像我一样)决定从所有基于多继承的解决方案中尽快逃脱,那么使用load_tests()从加载的套件中过滤基类可能会有以下问题:
在标准TestLoader中,从类自动加载完成后将调用load_tests。 因为:*此自动加载自类将尝试使用标准签名init(self,name)从基类构造实例,并且*您可能希望此基类具有完全不同的ctor签名,或者*由于某些其他原因,您可能希望跳过基类实例的构造-然后-移除
..您可能希望完全阻止从基类自动加载测试实例。
编辑:Vadim在其他线程中的解决方案是一种更优雅,简洁和独立的方法。 我已经实现了“嵌套类技巧”,并确认它可以很好地工作,以防止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方法(“ fixture”方法setUp * / tearDown * / cleanup *和测试方法本身)具有所有信息,这些信息定义了子TestCase类将要运行的非常特定的固定装置。
对我来说,这是一个临时解决方案,用于在单元测试中快速实现一些参数化的固定装置,因为我计划将团队的测试尽快迁移到pytest。