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

时间:2013-11-20 18:51:20

标签: python django mocking

我有一个很好的基础测试类,它扩展了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)

但这也是不可能的。

有没有办法避免这种重复并在超类上做补丁 哪个修补了所有子类方法?

1 个答案:

答案 0 :(得分:1)

最好使用元类,因为它比手动应用装饰器更容易处理测试用例的继承。沿着这些方向的东西(我没有测试它,但你应该得到这个想法):

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实现来定义其他基类。