Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

async pytest-bdd step definitions #195

Open
mathew-jithin opened this issue Nov 2, 2020 · 7 comments
Open

async pytest-bdd step definitions #195

mathew-jithin opened this issue Nov 2, 2020 · 7 comments

Comments

@mathew-jithin
Copy link

Just shooting this question with reference to pytest-dev/pytest-bdd#223

Is there any way the same can be handled with pytest-asyncio? Hope someone will please help if you have worked on something similar.

@mathew-jithin mathew-jithin changed the title async pytest-bdd steps async pytest-bdd step definitions Nov 2, 2020
@seifertm
Copy link
Contributor

seifertm commented Nov 2, 2020

My understanding is that there are two questions in the room:

  1. Does pytest-asyncio work with pytest-bdd when using async test steps?
  2. Can pytest-asyncio be used to provide support for async step definitions in pytest-bdd?

pytest-asyncio basically works like this: If an asynchronous test case is marked with the keyword asyncio, the plugin surrounds that test case with a synchronous wrapper. The wrapper executes the async function in an event loop. When you use the @when decorator, the decorated function will be synchronous:
https://github.com/pytest-dev/pytest-bdd/blob/02e667f239618e24dab6df787be43b670bcc9df8/pytest_bdd/steps.py#L105

Therefore, the decorated function cannot be executed in an event loop. In other words: No, I don't think pytest-bdd and pytest-asyncio can work together without modifications.

Here is the code that wraps the async function:

def wrap_in_sync(func, _loop):
"""Return a sync wrapper around an async function executing it in the
current event loop."""
@functools.wraps(func)
def inner(**kwargs):
coro = func(**kwargs)
if coro is not None:
task = asyncio.ensure_future(coro, loop=_loop)
try:
_loop.run_until_complete(task)
except BaseException:
# run_until_complete doesn't get the result from exceptions
# that are not subclasses of `Exception`. Consume all
# exceptions to prevent asyncio's warning from logging.
if task.done() and not task.cancelled():
task.exception()
raise
return inner

But it should be possible to make both plugins work together. For example, there is already a custom integration for Hypothesis:

if getattr(pyfuncitem.obj, 'is_hypothesis_test', False):
pyfuncitem.obj.hypothesis.inner_test = wrap_in_sync(
pyfuncitem.obj.hypothesis.inner_test,
_loop=pyfuncitem.funcargs['event_loop']
)

This solution relies on markers provided by Hypothesis. We could create a similar mechanism with the following steps:

  1. pytest-bdd needs to provide metadata for BDD steps decorated with when, given, …, so that pytest-asyncio can recognize them as such
  2. pytest-asyncio recognizes the fact that a @when decorator is present and wraps the underlying async function, instead of the decorator.

I personally don't like the approach, though, as we would implement pytest-bdd support as another special case. It would be much nicer to find a more general way for pytest-asyncio to play with other plugins. But I'm also not in the position to decide :)

@mathew-jithin
Copy link
Author

Thanks @seifertm. Really appreciate the response.

Saw this PR which still remains in review in pytest-bdd. Maybe if a similar handling is done in their side the issue can be addressed better.

@seifertm
Copy link
Contributor

seifertm commented Jan 7, 2022

At the time of writing pytest-asyncio is compatible with flaky and hypothesis. I think that compatibility with pytest-bdd is a reasonable feature request.
@Tinche Does it make sense to label this issue accordingly? I think labels would help keeping track of triaged issues. I'm thinking of the labels feature and interop, but I'm open to other solutions.

@Tinche Tinche added the feature label Jan 7, 2022
@Tinche
Copy link
Member

Tinche commented Jan 7, 2022

@seifertm Added the 'feature' label!

@KelvinSan
Copy link

Has this been done or is it still open ?

@seifertm
Copy link
Contributor

@KelvinSan There has been no progress on this from the pytest-asyncio side.

In the meantime, the pytest-bdd issue linked by the OP received some attention. One comment presents a "comaptibility decorator" for using pytest-bdd steps with pytest-asyncio.

@yazeedalrubyli

This comment was marked as off-topic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants