如何修补装饰器在 Python 的数据形状中注册的方法?

How do I patch a method registered by a decorator in Python's datashape?

我正在使用 datashape Python 包并使用 @datashape.discover.register 装饰器注册一个新类型。我想测试一下,当我在我正在注册的类型的对象上调用 datashape.discover 时,它会调用正在装饰的函数。我也想用良好的单元测试原则来做到这一点,这意味着不实际执行被装饰的功能,因为它会产生我不希望在测试中产生的副作用。但是,这不起作用。

下面是一些演示问题的示例代码:

myfile.py:

@datashape.discover.register(SomeType)
def discover_some_type(data)
    ...some stuff i don't want done in a unit test...

test_myfile.py:

class TestDiscoverSomeType(unittest.TestCase):
    @patch('myfile.discover_some_type')
    def test_discover_some_type(self, mock_discover_some_type):
        file_to_discover = SomeType()

        datashape.discover(file_to_discover)

        mock_discover_some_type.assert_called_with(file_to_discover)

问题似乎是我想要模拟的函数在测试主体中被模拟了,但是,它在装饰时(即导入时)没有被模拟。 discover.register 函数本质上是在内部注册被修饰的函数,以便在使用给定类型的参数调用 discover() 时查找它。不幸的是,它似乎每次都在内部注册real函数,而不是我想要的补丁版本,所以它总是会调用real函数。

关于如何能够修补被修饰的函数并断言它在调用 datashape.discover 时被调用的任何想法?

这是我发现的一个解决方案,只是有点老套:

sometype.py:

def discover_some_type(data):
    ...some stuff i don't want done in a unit test...

discovery_channel.py:

import sometype

@datashape.discover.register(SomeType)
def discover_some_type(data):
    return sometype.discover_some_type(data)

测试_sometype.py:

class TestDiscoverSomeType(unittest.TestCase):
    @patch('sometype.discover_some_type')
    def test_discover_some_type(self, mock_discover_some_type):
        import discovery_channel

        file_to_discover = SomeType()

        datashape.discover(file_to_discover)

        mock_discover_some_type.assert_called_with(file_to_discover)

关键是你必须修补任何实际会做的事情在你导入模块之前你导入具有修饰函数的模块,该修饰函数将注册修补函数到数据形状。不幸的是,这意味着您不能在同一个模块中拥有装饰函数和进行发现的函数(因此逻辑上应该放在一起的东西现在分开了)。并且您在单元测试中有一些有点古怪的函数导入(触发 discover.register)。但至少 它有效