starlette: pytest event loop is already running
Because the test client calls loop.run_until_complete(connection(receive, send)), I cannot use anything that modifies the event loop in a pytest fixture without getting RuntimeError: This event loop is already running.
I would like to use a package like aresponses to mock aiohttp requests like this:
@pytest.fixture
def mock_endpoint(aresponses):
aresponses.add('mock.com', '/test/', 'get', 'this is my mock response')
After messing with it for a couple hours, the only way I was able to get successful tests was to wrap the application in middleware:
@pytest.fixture
def app():
class App:
def __init__(self, app):
self.app = app
def __call__(self, scope):
return functools.partial(self.asgi, scope=scope)
async def asgi(self, receive, send, scope):
async with ResponsesMockServer() as aresponses:
aresponses.add('mock.com', '/test/', 'get', 'this is my mock response')
inner = self.app(scope)
await inner(receive, send)
return App(application)
@pytest.fixture
def test_client(app):
with TestClient(app) as test_client:
yield test_client
I am going to modify this to allow myself to dynamically pass responses through the @pytest.mark decorator, but this workflow is not really convenient at all.
Am I missing something here? Is there a better way to set up my test clients, or should I just keep going down this route?
Thanks
<picture> <source media="(prefers-color-scheme: dark)" srcset="https://polar.sh/api/github/encode/starlette/issues/440/pledge.svg?darkmode=1">[!IMPORTANT]
- We’re using Polar.sh so you can upvote and help fund this issue.
- We receive the funding once the issue is completed & confirmed by you.
- Thank you in advance for helping prioritize & fund our backlog.
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 6
- Comments: 23 (8 by maintainers)
Commits related to this issue
- Draft for the async test client (#440) — committed to gvbgduh/starlette by gbgduh 5 years ago
Just FYI, I’m also stumbling over this currently trying to use the
TestClientin anasynctest function (withpytest-asyncio). Minimal test case:Fails with “RuntimeError: This event loop is already running” too. I guess there is currently no workaround, aside from just not using
asynctests, which I think wouldn’t work in my specific case.Thank you for working on this!
I have a similar problem where I’m also trying to embed a database connection with a transaction active for the current test in the
request.state. I haven’t quite found the magic configuration ofpytest,pytest-asyncio, andTestClientto make this work yet.Basically, I’d love to see an example of how to use TestClient along with databases/asyncpg.
@taybin - I just found this library, after much wailing and gnashing of teeth with errors like the one in this issue. It worked for me; hope it helps you, too.
EDIT: Just realized I responded in a different issue than I meant to about a similar problem, but I’ll leave it in case it’s helpful.
Found a workaround from some other issue.
at the top of the code.
I only use the httpx-based client as described in https://github.com/encode/starlette/issues/652#issuecomment-569327566 and it works very well. Together with
asgi-lifespan, also startup and shutdown tasks are executed: https://github.com/florimondmanca/asgi-lifespanI used the starlette TestClient with nest_asyncio as a workaround for this problem, but I changed to use async-asgi-testclient. It works very well so far.
@dmontagu Hey, this library is on MIT license now 😃
I had a similar problem running pytest and the ASGI server in the same event loop and found this solution don’t know if it’s useful for you. Still gives some warning about files still open when closing the server
Okay - that’s kinda awkward.
It’s a bit of a side effect of the fact that the existing TestClient exposes a sync interface. See also https://github.com/encode/databases/issues/32#issuecomment-465728135
Given that I’ve just released this… https://github.com/encode/requests-async one thing we could look at doing would be moving to having an
asynctest client (requests-async, but with an ASGI adapter) and usingasynctest cases. (pytest-asyncio seems to have that covered.)