I'm trying to test a click command that is async from pytest, but I am hitting the limits of my knowledge of asyncio (or approaching the problem with a wrong architecture)
On one side, I have a click command line, that creates a grpclib channel to hit a grpc api.
import asyncio
from grpclib import Channel
from functools import wraps
def async_cmd(func):
@wraps(func)
def wrapper(*args, **kwargs):
return asyncio.run(func(*args, **kwargs))
return wrapper
@click.command
@async_cmd
async def main():
async with Channel('127.0.0.1', 1234) as channel:
blah = await something(channel)
do_stuff_with(blah)
return 0
Now I'm trying to test things using pytest and pytest-asyncio:
from click.testing import CliRunner
from cli import main
from grpclib.testing import ChannelFor
import pytest
@pytest.mark.asyncio
async def test_main()
async with ChannelFor([Service()]) as test_channel:
# Plan is to eventually mock grpclib.Channel with test_channel here.
runner = CliRunner()
runner.invoke(main)
My issue is that the async_cmd around main expects to call asyncio.run.
But by the time the test_main method is called, a loop is already running (launched by pytest).
What should I do?
- Should I modify my wrapper to join an existing loop (and how so?).
- Should I mock something somewhere?
- Should I just change my code do have my
mainjust responsible for parsing the arguments and calling another function?