如何模拟和测试装饰器?

时间:2020-09-28 16:36:00

标签: python unit-testing mocking python-unittest python-unittest.mock

如何测试以下调用第3方库的装饰器?

import third_party_lib
import functools

class MyDecorator:
    def __init__(self, ....):
        self.third_party_lib = ThirdPartyLib(....) # will create a 3rd party instance

    def __call__(self, ...):
        def decorator(f):
            @functools.wraps(f)
            def wrap(*arg, **kwargs):
                result = f(*arg, **kwargs)
                # ....
                a = self.third_party_lib.send(value=result).get()
                # ....
                return result
            return wrap
        return decorator

我需要创建一个单元测试来断言third_party_lib.send()是否被装饰器装饰了。理想情况下,还要确保将测试功能的结果传递给该功能。

decorator = MyDecorator(....)

@decorator(....)
def test_func():
    ret = ...
    return ret # ret should be passed to `third_party_lib.send()`

1 个答案:

答案 0 :(得分:1)

如果要验证是否正确调用了第三方函数,可以对其进行模拟并检查是否使用正确的参数调用了该模拟。如评论中所述,由于ThirdPartyLib初始化也应被模拟,因此您必须确保在设置模拟后构造docorator,例如通过在测试内部对其进行构造:

from unittest import mock

@mock.patch('third_party_lib.ThirdPartyLib')
def test_my_decorator(mocked_lib):
    decorator = MyDecorator()

    @decorator()
    def example_func():
        return 42

    example_func()
    mocked_lib.return_value.send.assert_called_once_with(value=42)

如果需要在更多测试中使用修饰的函数,则可以将其包装在函数中:

def decorated_func():
    decorator = MyDecorator()

    @decorator()
    def example_func():
        return 42

    return example_func

@mock.patch('third_party_lib.ThirdPartyLib')
def test_my_decorator(mocked_lib):
    decorated_func()()
    mocked_lib.return_value.send.assert_called_once_with(value=42)