如何通过自定义装饰器为pytest提供非fixture类型的测试参数
问题原因
适配Python3的高版本pytest会在执行测试前静态扫描测试函数的参数签名,校验每个参数是否有对应的fixture/参数化配置。你之前的自定义装饰器是运行时动态注入参数,没被pytest的静态扫描识别到,所以直接报fixture不存在的错误,和Python2运行正常的差异本质是pytest版本升级带来的校验逻辑变化。
方案1:最小改动适配现有装饰器,无需修改测试用例
只需要给装饰器加上pytest的参数化标记,提前告知pytesturl参数不需要匹配fixture,我们会自行注入:
from functools import wraps import pytest def with_mock_url(url=''): """ 启动MockEchoTestServer,把拼接好的服务地址作为url参数传给被装饰函数 """ def decorator(func): # 新增这一行:告诉pytest url参数已被参数化,不需要查找对应fixture func = pytest.mark.parametrize('url', [None])(func) @wraps(func) def decorated(*args, **kwargs): # 移除pytest默认传入的None占位值 kwargs.pop('url', None) with MockEchoTestServer().serve() as serveraddr: full_url = f"{serveraddr}/{url}" return func(*args, url=full_url, **kwargs) return decorated return decorator
该方案完全兼容原有测试用例的写法,不需要调整业务测试代码。
方案2:改造为pytest原生fixture实现(更推荐)
符合pytest的设计规范,后续维护性更强,实现方式如下:
第一步:定义fixture
import pytest @pytest.fixture def url(request): # 读取测试用例标记里传入的url后缀 url_path = request.node.get_closest_marker("with_mock_url").args[0] with MockEchoTestServer().serve() as serveraddr: yield f"{serveraddr}/{url_path}"
第二步:调整测试用例写法
只需要把原来的自定义装饰器换成pytest标记即可,测试逻辑完全不变:
@pytest.mark.with_mock_url('?status=404&content=test&content-type=csv') def test_file_not_found(self, url): res_id = self._test_resource(url)['id'] result = update_resource(None, res_id) assert not result, result self.assert_archival_error('Server reported status error: 404 Not Found', res_id)
内容的提问来源于stack exchange,提问作者ThrawnCA
相关产品推荐
相关产品推荐

