如何从父元类调用子类方法?测试框架setUp/TearDown问题
解决元类驱动测试运行器中子类方法未覆盖的问题
你的问题核心是:元类里包装测试方法时,错误调用了元类自身的before/after方法,而非子类实例的同名方法。
问题根源
在元类的replaced_fnc内部,self.before(self)里的self指的是元类的实例(也就是TestSuite这个类对象),不是你创建的TestSuite实例。所以不管子类怎么重写实例方法,调用的始终是元类里定义的before/after。
修复方案
修改包装函数,让它调用测试实例的before和after方法,而不是元类的方法。因为测试方法是实例方法,第一个参数就是实例本身(self),所以从args里取第一个元素即可。
修改后的完整代码:
class MetaTestCase(type): def __call__(self, *args, **kwds): return super().__call__(*args, **kwds) def __new__(cls, name, bases, attrs): def replaced_fnc(fn): def new_test(*args, **kwargs): # args[0]是TestSuite的实例,调用它的before/after test_instance = args[0] test_instance.before() result = fn(*args, **kwargs) test_instance.after() return result return new_test for attr_name in attrs: attr = attrs[attr_name] if callable(attr) and not attr_name.startswith('__'): # 排除魔术方法,避免意外包装 attrs[attr_name] = replaced_fnc(attr) return super(MetaTestCase, cls).__new__(cls, name, bases, attrs) # 可保留作为类级别的默认实现(按需选择) def before(self): print('Before') def after(self): print('After') class TestCase(metaclass=MetaTestCase): pass class TestSuite(TestCase): def before(self): print('New Before') def after(self): print('New After') def test(self): print("Test") if __name__ == "__main__": TS = TestSuite() TS.test()
关键修改点
- 在
new_test里,从args中获取测试实例(args[0]),调用它的before()和after() - 包装方法时排除了魔术方法(比如
__init__),避免不必要的包装导致问题 - 元类的
__new__方法参数里,把self改成cls(元类的__new__第一个参数是元类本身,用cls更规范)
运行结果
执行后会输出:
New Before Test New After
额外优化建议
如果希望子类可以选择不重写before/after时使用默认实现,更合理的方式是在TestCase类里定义实例级别的默认方法,而非元类:
class TestCase(metaclass=MetaTestCase): def before(self): print('Default Before') def after(self): print('Default After')
这样子类不重写的话就会使用这个默认实现,更符合测试框架的常见设计逻辑。
内容的提问来源于stack exchange,提问作者Alraku
相关产品推荐
相关产品推荐

