首页 > 解决方案 > 模拟装饰器函数以绕过装饰器逻辑

问题描述

我正在尝试为我的代码编写一些单元测试,而这些代码又使用了一个装饰器

import unittest
from unittest.mock import patch
from functools import wraps

def decorator(f):
    @wraps(f)
    def decorated(x):
        return f(x+1)
    return decorated

@decorator
def get_value(x):
    return x
    
class MyTestCase(unittest.TestCase):
    @patch('file.decorator', lambda f: f)
    def test_something(self):
        result = get_value(1)
        self.assertEqual(1, result)

我正在尝试模拟装饰函数以仅返回 f 并完全绕过装饰器逻辑部分。这在 Python 中的单元测试期间的覆盖装饰器中有所讨论,但并没有真正起作用。

标签: pythonpython-unittest

解决方案


由于装饰器在您定义后立即运行get_value,因此模拟装饰器为时已晚。但是,您可以做的(因为您使用functools.wraps)是模拟get_value本身并get_value.__wrapped__以某种方式使用(原始功能)。就像是

@patch('tmp.get_value', get_value.__wrapped__)
def test_something(self):
    result = get_value(1)
    self.assertEqual(1, result)

(在这种情况下,我将带有上述更改的原始代码放入 中tmp.py,并将其作为 运行python3 -munittest tmp.py,因此我修补了参考tmp.get_value。)

但是,如果您预计需要测试未修饰的原始版本,则将其保留在其自己的(私有)名称下进行测试可能更简单:无需修补。

import unittest
from functools import wraps

def decorator(f):
    @wraps(f)
    def decorated(x):
        return f(x+1)
    return decorated

def _get_value(x):
    return x

get_value = decorator(_get_value)
    
class MyTestCase(unittest.TestCase):
    def test_something(self):
        result = _get_value(1)
        self.assertEqual(1, result)

推荐阅读