如何通过自定义装饰器提供非夹具 pytest 参数?

Posted

技术标签:

【中文标题】如何通过自定义装饰器提供非夹具 pytest 参数?【英文标题】:How can I provide a non-fixture pytest parameter via a custom decorator? 【发布时间】:2022-01-08 16:05:34 【问题描述】:

我们有通过 Pytest 运行的单元测试,它使用自定义装饰器在每次测试之前启动上下文管理的模拟回显服务器,并将其地址作为额外参数提供给测试。这适用于 Python 2。

但是,如果我们尝试在 Python 3 上运行它们,那么 Pytest 会抱怨它找不到与额外参数名称匹配的夹具,并且测试会失败。

我们的测试看起来与此类似:

@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)

使用这样的装饰器函数:

from functools import wraps

def with_mock_url(url=''):
    """
    Start a MockEchoTestServer and call the decorated function with the server's address prepended to ``url``.
    """
    def decorator(func):
        @wraps(func)
        def decorated(*args, **kwargs):
             with MockEchoTestServer().serve() as serveraddr:
                 return func(*(args + ('%s/%s' % (serveraddr, url),)), **kwargs)
        return decorated
    return decorator

在 Python 2 上这有效;模拟服务器启动,测试获取类似于“http://localhost:1234/?status=404&content=test&content-type=csv”的 URL,然后模拟关闭。

然而,在 Python 3 上,我们得到一个错误,“fixture 'url' not found”。

有没有办法告诉 Python,“这个参数是从其他地方提供的,不需要固定装置”?或者是否有一种简单的方法可以将其变成固定装置?

【问题讨论】:

您可以尝试使用request 夹具***.com/questions/69852075/… 感谢您的提示,但这似乎是关于自定义固定装置的创建。在这种情况下,创建参数很容易;困难在于将其作为不是夹具的函数参数传递给测试。 【参考方案1】:

您可以使用url 作为args 参数

@with_mock_url('?status=404&content=test&content-type=csv')
def test_file_not_found(self, *url):
    url[0] # the test url

【讨论】:

这可能行得通,但会很笨重;每个受影响的函数都必须改变它的签名和它的一些行为,并且必须对参数排序做出假设,如果参数在未来发生变化,这些假设可能会改变。我会记住它作为备用选项,但如果我要达到那个长度,我可能会完全放弃装饰器并在每个测试中直接调用上下文管理器。【参考方案2】:

如果我为注入的参数添加默认值,Pytest 似乎满足于忽略它,使其成为非强制性:

@with_mock_url('?status=404&content=test&content-type=csv')
def test_file_not_found(self, url=None):

然后装饰器可以按预期注入值。

【讨论】:

以上是关于如何通过自定义装饰器提供非夹具 pytest 参数?的主要内容,如果未能解决你的问题,请参考以下文章

@Patch 装饰器与 pytest 夹具不兼容

python/pytest命令行自定义参数(pytest-fixture装饰器)

如何参数化 Pytest 夹具

如何在pytest中将几个参数化的夹具连接成一个新的夹具?

如何通过自定义装饰器记录@Input@Output值的值。

pytest常用装饰器