测试用例参数化再加装饰器会使参数化失效

问题描述

在测试用例中使用参数化,在@pytest.mark.parametrize()上方加入装饰器来抓取运行报错信息,但是加入装饰器后参数化失效了。如图:

wecom-temp-30576-5df4b5edcb3e5c8861a0d2eb298dd333

出现原因

装饰器改变了函数的签名或行为,导致 pytest 无法正确识别和处理参数化的测试用例。

  1. 装饰器没有正确保留被装饰函数的元信息
    pytest 使用函数的元信息(例如 __name____doc__)来识别测试用例。未经特殊处理的装饰器会改变这些元信息,从而导致 pytest 无法识别测试用例。示例:

    def my_decorator(func):
        def wrapper(*args, **kwargs):
            print("Before the test")
            result = func(*args, **kwargs)
            print("After the test")
            return result
        return wrapper
    

    装饰后,函数 func 的元信息就被替换成了 wrapper 的元信息。

  2. 装饰器改变了函数签名
    pytest.mark.parametrize 需要知道测试函数的参数列表。如果装饰器改变了函数签名,pytest 将无法为测试函数提供正确的参数。

解决办法

为了避免这些问题,可以使用 Python 内置的 functools.wraps 来修饰装饰器,保留原函数的元信息和签名。

import pytest
from functools import wraps

def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print("Before the test")
        result = func(*args, **kwargs)
        print("After the test")
        return result
    return wrapper

@pytest.mark.parametrize("x, y, expected", [(1, 1, 2), (2, 2, 4)])
@my_decorator
def test_add(x, y, expected):
    assert x + y == expected