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

Usage gino in fastapi/starlette tests #706

Closed
Smosker opened this issue Jul 9, 2020 · 2 comments
Closed

Usage gino in fastapi/starlette tests #706

Smosker opened this issue Jul 9, 2020 · 2 comments

Comments

@Smosker
Copy link

Smosker commented Jul 9, 2020

GINO version:1.0.1
Python version: 3.7
asyncpg version: 0.18.3

Description

Hello! I'm trying to figure out how to work with gino in tests of my fastapi app.
I'm following this tutorial https://python-gino.org/docs/en/1.0/tutorials/fastapi.html#

My goal is to be able to do something like this:

from myapp.db import MyModel

@pytest.mark.asyncio
async def test_smth(client):
  obj = await MyModel.create(name='test')
  response = client.get(
       f'api/objects/{obj.id}/'
   )
....

But for now i cant figure out how to initialize gino correctly to work with db inside tests

my client fixture look like this

@pytest.fixture
def client(app):
   from myapp.app import get_app
    migrate_db()
    with TestClient(get_app() as client:
        yield client
    unmigrate_db()

where get_app is

def get_app():
    app = FastAPI()
    db.init_app(app)
    return app

What I Did

I tried just running code above, receive:

asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress

i tried to create own pool and create object using it

from gino.ext.starlette import Gino
from myapp.config import config

@pytest.mark.asyncio
async def test_smth(client):
    db = Gino()
    async with db.with_bind(bind=config['dsn']) as engine:
        obj = await MyModel.create(
            name='test'
            bind=engine
        )
    response = client.get(
        f'api/objects/{obj.id}/'
    )

it actually works and object was created
but on line response = client.get( i get

requests/requests/sessions.py:543: in get
    return self.request('GET', url, **kwargs)
starlette/starlette/testclient.py:429: in request
    json=json,
requests/requests/sessions.py:530: in request
    resp = self.send(prep, **send_kwargs)
requests/requests/sessions.py:643: in send
    r = adapter.send(request, **kwargs)
starlette/starlette/testclient.py:243: in send
    raise exc from None
starlette/starlette/testclient.py:240: in send
    loop.run_until_complete(self.app(scope, receive, send))
python3/src/Lib/asyncio/base_events.py:563: in run_until_complete
    self._check_runnung()
python3/src/Lib/asyncio/base_events.py:523: in _check_runnung
    raise RuntimeError('This event loop is already running')

Can you give me advise of how to do it correctly?

@Smosker
Copy link
Author

Smosker commented Jul 9, 2020

Figure it out with some search:

  1. swap fastapi testclient with HTTPX-based TestClient? encode/starlette#652 (comment)
  2. install pytest-asyncio
  3. use like this:
@pytest.fixture
async def db_bind():
    db = Gino()
    return db.with_bind(bind=config['dsn'])



@pytest.fixture
async def my_object(db_bind):
    async with db_bind as engine:
        return await MyModel.create(
            name='test'
            bind=engine
        )

@pytest.mark.asyncio
async def test_get_obj(client, my_object):
    response = await client.get(
        f'api/objects/{obj.id}/'
    )
    assert response.status_code == 200, response.text
    data = response.json()
    assert data['name'] == my_object.name

@vobinics
Copy link

Hello! To fix this use the async client async-asgi-testclient

@wwwjfy wwwjfy closed this as completed Aug 25, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants