Python 继承修补过的类

Python 继承修补过的类,python,python-2.7,python-unittest,python-mock,Python,Python 2.7,Python Unittest,Python Mock,我有一个扩展unittest.TestCase的基类,我想修补这个基类,这样扩展这个基类的类也会应用修补程序 代码示例: @patch("some.core.function", mocked_method) class BaseTest(unittest.TestCase): #methods pass class TestFunctions(BaseTest): #methods pass 修补TestFunctions类直接起作用,但修补

我有一个扩展unittest.TestCase的基类,我想修补这个基类,这样扩展这个基类的类也会应用修补程序

代码示例:

@patch("some.core.function", mocked_method)
class BaseTest(unittest.TestCase):
      #methods
      pass

class TestFunctions(BaseTest):
      #methods
      pass

修补
TestFunctions
类直接起作用,但修补BaseTest类不会改变
TestFunctions
some.core.function
的功能

一般来说,我更喜欢在家里做这类事情。您可以通过使用该方法(或者,将补丁的
停止
方法注册为)确保在测试完成后清除补丁:


如果您有足够的纪律性,总是在重写的
设置
方法中调用
super
,那么它应该可以正常工作。

您可能需要一个元类:元类只是定义类的创建方式。 默认情况下,所有类都是使用Python的内置类
类型创建的:

>>> class Foo:
...     pass
...
>>> type(Foo)
<class 'type'>
>>> isinstance(Foo, type)
True
我们需要控制类的创建,因此我们要覆盖
类型。\uuuuu new\uuuuu
这里,并在所有新实例上使用
补丁
装饰器:

class PatchMeta(type):
    """A metaclass to patch all inherited classes."""

    def __new__(meta, name, bases, attrs):
        cls = type.__new__(meta, name, bases, attrs)
        cls = patch("some.core.function", mocked_method)(cls)
        return cls
现在,您只需使用
\uuuuuuuuuuuuuuuuuuuuuuu=PatchMeta
设置元类:

class BaseTest(unittest.TestCase):
    __metaclass__ = PatchMeta
    # methods
问题在于这一行:

cls = patch("some.core.function", mocked_method)(cls)
所以目前我们总是用参数
“some.core.function”
mock\u方法来装饰。
相反,您可以使其使用类的属性,如下所示:

cls = patch(*cls.patch_args)(cls)
然后将
patch_args
添加到您的类中:

class BaseTest(unittest.TestCase):
    __metaclass__ = PatchMeta
    patch_args = ("some.core.function", mocked_method)

Edit:正如@mgilson在评论中提到的,
patch()
修改类的方法,而不是返回新类。因此,我们可以将
\uuuuu new\uuuu
替换为
\uuuu init\uuuu

class PatchMeta(type):
    """A metaclass to patch all inherited classes."""

    def __init__(cls, *args, **kwargs):
        super(PatchMeta, self).__init__(*args, **kwargs)
        patch(*cls.patch_args)(cls)

这无疑更干净。

这可能是你想在谷歌上搜索并继续阅读的地方,直到你了解它们是如何工作的。元类是由子类继承的,装饰器只装饰它们所使用的类。啊,我想我有点理解你的意思。补丁只出现在类的实例上?不,
patch
是一个装饰器,它只直接将类放在它下面并装饰该类。现在任何子类都不会被修饰,它们只是普通类。元类控制类的创建方式,因此可以在类首次创建时对其进行修补。在基类的元类被设置之后,元类也会作用于子类,所以子类也会被修补。您使用的是Python2还是Python3?这通常是一个需要添加的相关标签。感谢您提供的信息。蟒蛇2。我会再调查一下的啊!我刚刚得出了一个类似的结论,但相反,我检查了从
test
开始的所有函数,并对它们进行了模拟。你的看起来更优雅。这两种方法都有优点/缺点吗?有可能有一个以上的元类吗?或者我需要某种形式的“启始”吗?@sihrc为什么你想要比无元类更多的元类?我从来没有遇到过这样的需要,你可能在这里做错了什么。我不认为有那么多的缺点。啊,我打赌我可以添加另一个元类,它接受一堆补丁,并生成一个完成所有补丁的PatchClass?啊,我想我知道哪里会出现混乱。
补丁程序
装饰程序不返回新类。它返回旧类,其中包含以
test
patched开头的所有方法。我不建议您使用
self=patch(…)(self)
——这太令人困惑了。我建议只使用
patch(…)(self)
,因为
patch
返回的值在类上运行(然后返回,因为这是装饰程序所做的)。我认为这也有其优点。我也从来没有见过这样做的补丁。非常感谢!
class BaseTest(unittest.TestCase):
    __metaclass__ = PatchMeta
    patch_args = ("some.core.function", mocked_method)
class PatchMeta(type):
    """A metaclass to patch all inherited classes."""

    def __init__(cls, *args, **kwargs):
        super(PatchMeta, self).__init__(*args, **kwargs)
        patch(*cls.patch_args)(cls)