我怎样才能重写这个夹具调用,这样它就不会被直接调用?
How can I rewrite this fixture call so it won't be called directly?
我在测试文件中定义了以下夹具:
import os
from dotenv import load_dotenv, find_dotenv
from packaging import version # for comparing version numbers
load_dotenv(find_dotenv())
VERSION = os.environ.get("VERSION")
API_URL = os.environ.get("API_URL")
@pytest.fixture()
def skip_before_version():
"""
Creates a fixture that takes parameters
skips a test if it depends on certain features implemented in a certain version
:parameter target_version:
:parameter type: string
"""
def _skip_before(target_version):
less_than = version.parse(current_version) < version.parse(VERSION)
return pytest.mark.skipif(less_than)
return _skip_before
skip_before = skip_before_version()("0.0.1")
我想在某些测试中使用 skip_before
作为夹具。我这样称呼它:
#@skip_before_version("0.0.1") # tried this before and got the same error, so tried reworking it...
@when(parsers.cfparse("{categories} are added as categories"))
def add_categories(skip_before, create_tree, categories): # now putting the fixture alongside parameters
pass
当我运行这个时,我得到以下错误:
Fixture "skip_before_version" called directly. Fixtures are not meant to be called directly,
but are created automatically when test functions request them as parameters.
See https://docs.pytest.org/en/stable/fixture.html for more information about fixtures, and
https://docs.pytest.org/en/stable/deprecations.html#calling-fixtures-directly about how to update your code.
这怎么还是直接调用?我该如何解决这个问题?
如果我理解你的目标是正确的,你希望能够跳过基于版本限制说明符的测试。有很多方法可以做到这一点;我可以建议一个 autouse fixture,它将根据自定义标记条件跳过测试。示例:
import os
import pytest
from packaging.specifiers import SpecifierSet
VERSION = "1.2.3" # read from environment etc.
@pytest.fixture(autouse=True)
def skip_based_on_version_compat(request):
# get the version_compat marker
version_compat = request.node.get_closest_marker("version_compat")
if version_compat is None: # test is not marked
return
if not version_compat.args: # no specifier passed to marker
return
spec_arg = version_compat.args[0]
spec = SpecifierSet(spec_arg)
if VERSION not in spec:
pytest.skip(f"Current version {VERSION} doesn't match test specifiers {spec_arg!r}.")
夹具 skip_based_on_version_compat
将在每次测试时调用,但只有在测试标记为 @pytest.mark.version_compat
时才会执行某些操作。示例测试:
@pytest.mark.version_compat(">=1.0.0")
def test_current_gen():
assert True
@pytest.mark.version_compat(">=2.0.0")
def test_next_gen():
raise NotImplementedError()
使用VERSION = "1.2.3"
,第一个测试将被执行,第二个将被跳过。注意调用 pytest.skip
以立即跳过测试。在固定装置中返回 pytest.mark.skip
不会给您带来任何好处,因为标记已经在很久之前就已经被评估了。
此外,我注意到您正在编写小黄瓜测试(大概使用 pytest-bdd
)。通过上述方法,跳过整个场景应该也是可以的:
@pytest.mark.version_compat(">=1.0.0")
@scenario("my.feature", "my scenario")
def test_scenario():
pass
或者,您可以在功能文件中标记场景:
Feature: Foo
Lorem ipsum dolor sit amet.
@version_compat(">=1.0.0")
Scenario: doing future stuff
Given foo is implemented
When I see foo
Then I do bar
并使用 pytest-bdd
-own hooks:
def pytest_bdd_apply_tag(tag, function):
matcher = re.match(r'^version_compat\("(?P<spec_arg>.*)"\)$', tag)
spec_arg = matcher.groupdict()["spec_arg"]
spec = SpecifierSet(spec_arg)
if VERSION not in spec:
marker = pytest.mark.skip(
reason=f"Current version {VERSION} doesn't match restriction {spec_arg!r}."
)
marker(function)
return True
不幸的是,自定义固定装置和标记都无法在单个步骤中跳过(并且您仍然会跳过整个场景,因为它是小黄瓜中的原子测试单元)。我没有找到一种可靠的方法来使 pytest-bdd
步骤与 pytest 的东西成为朋友;看起来他们只是被忽略了。不过,您可以轻松地编写一个自定义装饰器来达到相同的目的:
import functools
def version_compat(spec_arg):
def deco(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
spec = SpecifierSet(spec_arg)
if VERSION not in spec:
pytest.skip(f"Current version {VERSION} doesn't match test specifiers {spec_arg!r}.")
return func(*args, **kwargs)
return wrapper
return deco
在一个步骤中使用 version_compat
deco:
@when('I am foo')
@version_compat(">=2.0.0")
def i_am_foo():
...
注意顺序 - 将装饰器放在 pytest-bdd
自己的东西之外不会触发它们(我想值得提出一个问题,但是嗯)。
我在测试文件中定义了以下夹具:
import os
from dotenv import load_dotenv, find_dotenv
from packaging import version # for comparing version numbers
load_dotenv(find_dotenv())
VERSION = os.environ.get("VERSION")
API_URL = os.environ.get("API_URL")
@pytest.fixture()
def skip_before_version():
"""
Creates a fixture that takes parameters
skips a test if it depends on certain features implemented in a certain version
:parameter target_version:
:parameter type: string
"""
def _skip_before(target_version):
less_than = version.parse(current_version) < version.parse(VERSION)
return pytest.mark.skipif(less_than)
return _skip_before
skip_before = skip_before_version()("0.0.1")
我想在某些测试中使用 skip_before
作为夹具。我这样称呼它:
#@skip_before_version("0.0.1") # tried this before and got the same error, so tried reworking it...
@when(parsers.cfparse("{categories} are added as categories"))
def add_categories(skip_before, create_tree, categories): # now putting the fixture alongside parameters
pass
当我运行这个时,我得到以下错误:
Fixture "skip_before_version" called directly. Fixtures are not meant to be called directly,
but are created automatically when test functions request them as parameters.
See https://docs.pytest.org/en/stable/fixture.html for more information about fixtures, and
https://docs.pytest.org/en/stable/deprecations.html#calling-fixtures-directly about how to update your code.
这怎么还是直接调用?我该如何解决这个问题?
如果我理解你的目标是正确的,你希望能够跳过基于版本限制说明符的测试。有很多方法可以做到这一点;我可以建议一个 autouse fixture,它将根据自定义标记条件跳过测试。示例:
import os
import pytest
from packaging.specifiers import SpecifierSet
VERSION = "1.2.3" # read from environment etc.
@pytest.fixture(autouse=True)
def skip_based_on_version_compat(request):
# get the version_compat marker
version_compat = request.node.get_closest_marker("version_compat")
if version_compat is None: # test is not marked
return
if not version_compat.args: # no specifier passed to marker
return
spec_arg = version_compat.args[0]
spec = SpecifierSet(spec_arg)
if VERSION not in spec:
pytest.skip(f"Current version {VERSION} doesn't match test specifiers {spec_arg!r}.")
夹具 skip_based_on_version_compat
将在每次测试时调用,但只有在测试标记为 @pytest.mark.version_compat
时才会执行某些操作。示例测试:
@pytest.mark.version_compat(">=1.0.0")
def test_current_gen():
assert True
@pytest.mark.version_compat(">=2.0.0")
def test_next_gen():
raise NotImplementedError()
使用VERSION = "1.2.3"
,第一个测试将被执行,第二个将被跳过。注意调用 pytest.skip
以立即跳过测试。在固定装置中返回 pytest.mark.skip
不会给您带来任何好处,因为标记已经在很久之前就已经被评估了。
此外,我注意到您正在编写小黄瓜测试(大概使用 pytest-bdd
)。通过上述方法,跳过整个场景应该也是可以的:
@pytest.mark.version_compat(">=1.0.0")
@scenario("my.feature", "my scenario")
def test_scenario():
pass
或者,您可以在功能文件中标记场景:
Feature: Foo
Lorem ipsum dolor sit amet.
@version_compat(">=1.0.0")
Scenario: doing future stuff
Given foo is implemented
When I see foo
Then I do bar
并使用 pytest-bdd
-own hooks:
def pytest_bdd_apply_tag(tag, function):
matcher = re.match(r'^version_compat\("(?P<spec_arg>.*)"\)$', tag)
spec_arg = matcher.groupdict()["spec_arg"]
spec = SpecifierSet(spec_arg)
if VERSION not in spec:
marker = pytest.mark.skip(
reason=f"Current version {VERSION} doesn't match restriction {spec_arg!r}."
)
marker(function)
return True
不幸的是,自定义固定装置和标记都无法在单个步骤中跳过(并且您仍然会跳过整个场景,因为它是小黄瓜中的原子测试单元)。我没有找到一种可靠的方法来使 pytest-bdd
步骤与 pytest 的东西成为朋友;看起来他们只是被忽略了。不过,您可以轻松地编写一个自定义装饰器来达到相同的目的:
import functools
def version_compat(spec_arg):
def deco(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
spec = SpecifierSet(spec_arg)
if VERSION not in spec:
pytest.skip(f"Current version {VERSION} doesn't match test specifiers {spec_arg!r}.")
return func(*args, **kwargs)
return wrapper
return deco
在一个步骤中使用 version_compat
deco:
@when('I am foo')
@version_compat(">=2.0.0")
def i_am_foo():
...
注意顺序 - 将装饰器放在 pytest-bdd
自己的东西之外不会触发它们(我想值得提出一个问题,但是嗯)。