Skip to main content
 首页 » 编程设计

python之修补 Python 子类中的所有方法

2025年05月04日7落叶无声

我有很好的基础测试类,它从 django 测试用例和另一个类扩展而来:

 class MyTestCase(TestCase, TestFreshProvisionedEachTest): 

现在一切正常,只是为了让它正常工作,我们必须(使用 Foord 的模拟库)修补中间件中的几个函数。

我的想法是这会工作得很好:

@patch('spotlight.middleware.extract_host_name', new=lambda host_name: 
TEST_DOMAIN) 
@patch('spotlight.middleware.extract_host_key', new=lambda host_key: 
company_name_to_db(TEST_DOMAIN)) 
class MyTestCase(TestCase, TestFreshProvisionedEachTest): 

不过好像不行,子类的方法没有打补丁。 我当时想可能有一种方法可以做类似的事情

MyTestCase = patch(MyTestCase, 'spotlight.middleware.extract_host_name', new=lambda host_name: TEST_DOMAIN) 

但这也是不可能的。

有没有办法避免这种重复并在父类(super class)上打补丁 哪个也修补所有子类方法?

请您参考如下方法:

最好为此使用元类,因为它比手动应用装饰器更容易处理测试用例的继承。类似这些(我还没有测试过,但你应该明白了):

class TestMeta(type(TestCase)): 
    def patch_method(cls, meth): 
        raise NotImplementedError 
 
    def __new__(mcls, name, bases, dct): 
        to_patch = [] 
 
        for methname, meth in dct.items(): 
            if methname.startswith('test') and callable(meth): 
                to_patch.append(methname) 
 
        cls = super().__new__(mcls, name, bases, dct) 
 
        for methname in to_patch: 
            meth = getattr(cls, methname) 
            meth = cls.patch_method(meth) 
            setattr(cls, methname, meth) 
 
        return cls 
 
class PatchedTestCase(TestCase, metaclass=TestMeta): 
    @classmethod 
    def patch_method(cls, meth): 
        meth = patch('spotlight.middleware.extract_host_name',  
                     new=lambda host_name: TEST_DOMAIN)(meth) 
 
        meth = patch('spotlight.middleware.extract_host_key',  
                     new=lambda host_key: company_name_to_db(TEST_DOMAIN))(meth) 
 
        return meth 
 
class MyTestCase(PatchedTestCase, TestFreshProvisionedEachTest): 
    ... 

通过这种方法,PatchedTestCase 的所有子类的所有方法都将被修补。您还可以使用不同的 patch_method 实现定义其他基类。