Bare async step implementation
This commit is contained in:
parent
0fab820f53
commit
d12403e469
|
@ -425,6 +425,24 @@ tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
|
|||
[package.extras]
|
||||
testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest-asyncio"
|
||||
version = "0.21.1"
|
||||
description = "Pytest support for asyncio"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pytest-asyncio-0.21.1.tar.gz", hash = "sha256:40a7eae6dded22c7b604986855ea48400ab15b069ae38116e8c01238e9eeb64d"},
|
||||
{file = "pytest_asyncio-0.21.1-py3-none-any.whl", hash = "sha256:8666c1c8ac02631d7c51ba282e0c69a8a452b211ffedf2599099845da5c5c37b"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pytest = ">=7.0.0"
|
||||
|
||||
[package.extras]
|
||||
docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"]
|
||||
testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest-xdist"
|
||||
version = "3.3.1"
|
||||
|
@ -553,4 +571,4 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess
|
|||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = ">=3.8"
|
||||
content-hash = "b2ba37df5fea186a1726b64f9c426661c8b228b3b6f9954eeba805e7653a087c"
|
||||
content-hash = "a060ad36b10706adf9d533433154ce45a0282675dbb9d9873cf3162a152cb8e1"
|
||||
|
|
|
@ -48,6 +48,7 @@ types-setuptools = "^65.5.0.2"
|
|||
pytest-xdist = "^3.0.2"
|
||||
coverage = {extras = ["toml"], version = "^6.5.0"}
|
||||
Pygments = "^2.13.0" # for code-block highlighting
|
||||
pytest-asyncio = "^0.21.1"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
|
|
|
@ -12,7 +12,9 @@ test_publish_article = scenario(
|
|||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import contextlib
|
||||
import functools
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
|
@ -120,6 +122,19 @@ def get_step_function(request, step: Step) -> StepFunctionContext | None:
|
|||
return None
|
||||
|
||||
|
||||
def ensure_sync(fn):
|
||||
"""Convert async function to sync function."""
|
||||
__tracebackhide__ = True
|
||||
if not asyncio.iscoroutinefunction(fn):
|
||||
return fn
|
||||
|
||||
@functools.wraps(fn)
|
||||
def wrapper(*args, **kwargs):
|
||||
return asyncio.run(fn(*args, **kwargs))
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
def _execute_step_function(
|
||||
request: FixtureRequest, scenario: Scenario, step: Step, context: StepFunctionContext
|
||||
) -> None:
|
||||
|
@ -156,7 +171,8 @@ def _execute_step_function(
|
|||
|
||||
request.config.hook.pytest_bdd_before_step_call(**kw)
|
||||
# Execute the step as if it was a pytest fixture, so that we can allow "yield" statements in it
|
||||
return_value = call_fixture_func(fixturefunc=context.step_func, request=request, kwargs=kwargs)
|
||||
step_func = ensure_sync(context.step_func)
|
||||
return_value = call_fixture_func(fixturefunc=step_func, request=request, kwargs=kwargs)
|
||||
except Exception as exception:
|
||||
request.config.hook.pytest_bdd_step_error(exception=exception, **kw)
|
||||
raise
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
import textwrap
|
||||
|
||||
|
||||
# TODO: Split this test in one that checks that we work correctly
|
||||
# with the pytest-asyncio plugin, and another that checks that we correctly
|
||||
# run async steps.
|
||||
def test_async_steps(pytester):
|
||||
"""Test parent given is collected.
|
||||
|
||||
Both fixtures come from the parent conftest.
|
||||
"""
|
||||
pytester.makefile(
|
||||
".feature",
|
||||
async_feature=textwrap.dedent(
|
||||
"""\
|
||||
Feature: A feature
|
||||
Scenario: A scenario
|
||||
Given There is an async object
|
||||
|
||||
When I do an async action
|
||||
|
||||
Then the async object value should be "async_object"
|
||||
And [async] the async object value should be "async_object"
|
||||
And the another async object value should be "another_async_object"
|
||||
"""
|
||||
),
|
||||
)
|
||||
|
||||
pytester.makepyfile(
|
||||
textwrap.dedent(
|
||||
"""\
|
||||
from pytest_bdd import given, parsers, scenarios, then, when
|
||||
import asyncio
|
||||
import pytest
|
||||
|
||||
scenarios("async_feature.feature")
|
||||
|
||||
@pytest.fixture
|
||||
async def another_async_object():
|
||||
await asyncio.sleep(0.01)
|
||||
return "another_async_object"
|
||||
|
||||
@given("There is an async object", target_fixture="async_object")
|
||||
async def given_async_obj():
|
||||
await asyncio.sleep(0.01)
|
||||
return "async_object"
|
||||
|
||||
@when("I do an async action")
|
||||
async def when_i_do_async_action():
|
||||
await asyncio.sleep(0.01)
|
||||
|
||||
@then(parsers.parse('the async object value should be "{value}"'))
|
||||
async def the_sync_object_value_should_be(async_object, value):
|
||||
assert async_object == value
|
||||
|
||||
@then(parsers.parse('[async] the async object value should be "{value}"'))
|
||||
async def async_the_async_object_value_should_be(async_object, value):
|
||||
await asyncio.sleep(0.01)
|
||||
assert async_object == value
|
||||
|
||||
@then(parsers.parse('the another async object value should be "{value}"'))
|
||||
def the_another_async_object_value_should_be(another_async_object, value):
|
||||
assert another_async_object == value
|
||||
|
||||
"""
|
||||
)
|
||||
)
|
||||
result = pytester.runpytest("--asyncio-mode=auto")
|
||||
result.assert_outcomes(passed=1)
|
Loading…
Reference in New Issue