如何在 pytest *before* fixture 被计算之前跳过测试
How to skip a test in pytest *before* fixtures are computed
我有一个相当大的测试套件,它是用 pytest 编写的,用于对应用程序执行系统测试,包括服务器端和客户端之间的通信。测试有一个巨大的固定装置,它被初始化以包含有关服务器的信息,然后用于创建客户端对象和 运行 测试。服务器端可能支持不同的功能集,它通过属性反映出来,这些属性可能存在也可能不存在于由夹具初始化的服务器对象中。
现在,与 this question 非常相似,如果服务器对象中不存在必需的属性,我需要跳过某些测试。
到目前为止,我们一直这样做的方法是在测试中添加一个装饰器来检查属性,如果不存在则使用 pytest.skip
。
示例:
import functools
import pytest
def skip_if_not_feature(feature):
def _skip_if_not_feature(func):
@functools.wraps(func)
def wrapper(server, *args, **kwargs):
if not server.supports(feature):
pytest.skip("Server does not support {}".format(feature))
return func(server, *args, **kwargs)
return wrapper
return _skip_if_not_feature
@skip_if_not_feature("feature_A")
def test_feature_A(server, args...):
...
当其中一些测试有更多固定装置时,就会出现问题,其中一些具有相对耗时的设置,并且由于 pytest 的工作方式,装饰器代码会跳过它们 运行s 在 夹具设置之后,浪费了宝贵的时间。
示例:
@skip_if_not_feature("sync_db")
def test_sync_db(server, really_slow_db_fixture, args...):
...
我希望通过更快地跳过这些测试来将测试套件优化到 运行。
我只能想到两种方法:
- 重写装饰器不使用服务器 fixture,使其运行在 fixtures.
之前
- 运行 决定跳过测试的代码在服务器 fixture 的初始化和其余 fixture 的初始化之间。
我无法弄清楚粗体部分是否可行,以及如果可行如何实现。我已经浏览了 pytest 文档和 google / Whosebug 类似问题的结果,但一无所获。
您可以在测试中添加带有功能名称的自定义标记,并在需要时在 pytest_collection_modifyitems
中添加跳过标记。
在这种情况下,将跳过测试而不先加载夹具。
conftest.py
def pytest_configure(config):
config.addinivalue_line(
"markers",
"feature: mark test with the needed feature"
)
def pytest_collection_modifyitems(config, items):
for item in items:
feature_mark = item.get_closest_marker("feature")
if feature_mark and feature_mark.args:
feature = feature_mark.args[0]
if not server.supports(feature):
item.add_marker("skip")
test_db.py
@pytest.mark.feature("sync_db")
def test_sync_db(server, really_slow_db_fixture, args...):
...
当前装饰器的问题是,在装饰器完成之后,模块包含一个测试函数,其中一个或多个参数是特性。这些被 pytest 机制识别为特征,并被评估。
全在于你*args
你可以做的是让你的装饰者在意识到它将跳过这个测试时吐出一个 func(server)
而不是 func(server,*args, **kwargs)
。
这样跳过的函数将不会有其他固定装置,因此不会对其进行评估。
事实上,您甚至可以 return 而不是 func
一个更简单的空 lambda: None
,因为它无论如何都不会被测试。
我有一个相当大的测试套件,它是用 pytest 编写的,用于对应用程序执行系统测试,包括服务器端和客户端之间的通信。测试有一个巨大的固定装置,它被初始化以包含有关服务器的信息,然后用于创建客户端对象和 运行 测试。服务器端可能支持不同的功能集,它通过属性反映出来,这些属性可能存在也可能不存在于由夹具初始化的服务器对象中。
现在,与 this question 非常相似,如果服务器对象中不存在必需的属性,我需要跳过某些测试。
到目前为止,我们一直这样做的方法是在测试中添加一个装饰器来检查属性,如果不存在则使用 pytest.skip
。
示例:
import functools
import pytest
def skip_if_not_feature(feature):
def _skip_if_not_feature(func):
@functools.wraps(func)
def wrapper(server, *args, **kwargs):
if not server.supports(feature):
pytest.skip("Server does not support {}".format(feature))
return func(server, *args, **kwargs)
return wrapper
return _skip_if_not_feature
@skip_if_not_feature("feature_A")
def test_feature_A(server, args...):
...
当其中一些测试有更多固定装置时,就会出现问题,其中一些具有相对耗时的设置,并且由于 pytest 的工作方式,装饰器代码会跳过它们 运行s 在 夹具设置之后,浪费了宝贵的时间。
示例:
@skip_if_not_feature("sync_db")
def test_sync_db(server, really_slow_db_fixture, args...):
...
我希望通过更快地跳过这些测试来将测试套件优化到 运行。 我只能想到两种方法:
- 重写装饰器不使用服务器 fixture,使其运行在 fixtures. 之前
- 运行 决定跳过测试的代码在服务器 fixture 的初始化和其余 fixture 的初始化之间。
我无法弄清楚粗体部分是否可行,以及如果可行如何实现。我已经浏览了 pytest 文档和 google / Whosebug 类似问题的结果,但一无所获。
您可以在测试中添加带有功能名称的自定义标记,并在需要时在 pytest_collection_modifyitems
中添加跳过标记。
在这种情况下,将跳过测试而不先加载夹具。
conftest.py
def pytest_configure(config):
config.addinivalue_line(
"markers",
"feature: mark test with the needed feature"
)
def pytest_collection_modifyitems(config, items):
for item in items:
feature_mark = item.get_closest_marker("feature")
if feature_mark and feature_mark.args:
feature = feature_mark.args[0]
if not server.supports(feature):
item.add_marker("skip")
test_db.py
@pytest.mark.feature("sync_db")
def test_sync_db(server, really_slow_db_fixture, args...):
...
当前装饰器的问题是,在装饰器完成之后,模块包含一个测试函数,其中一个或多个参数是特性。这些被 pytest 机制识别为特征,并被评估。
全在于你*args
你可以做的是让你的装饰者在意识到它将跳过这个测试时吐出一个 func(server)
而不是 func(server,*args, **kwargs)
。
这样跳过的函数将不会有其他固定装置,因此不会对其进行评估。
事实上,您甚至可以 return 而不是 func
一个更简单的空 lambda: None
,因为它无论如何都不会被测试。