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

Items created in db_session not accessible with client_class #19

Open
AbdealiLoKo opened this issue Jul 3, 2019 · 4 comments
Open

Items created in db_session not accessible with client_class #19

AbdealiLoKo opened this issue Jul 3, 2019 · 4 comments

Comments

@AbdealiLoKo
Copy link

I have a conftest:

import os

import pytest
from flask_migrate import upgrade

from myapp import create_app, flask_app

@pytest.fixture(scope='session')
def database(request):
    uri = flask_app.config.get('SQLALCHEMY_DATABASE_URI')
    assert uri.startswith('sqlite:///'), 'In tests, use a Sqlite DB'
    sqlite_path = uri.replace('sqlite:///', '')
    if os.path.exists(sqlite_path):
        os.remove(sqlite_path)

    @request.addfinalizer
    def drop_database():
        os.remove(sqlite_path)

@pytest.fixture(scope='session')
def app(request, database):
    """
    Used by pytest-flask
    """
    app = create_app()
    with app.app_context():
        upgrade()
    return app


@pytest.fixture(scope='session')
def _db(request, app):
    """
    Used by pytest-flask-sqlalchemy
    """
    db = app.extensions['sqlalchemy'].db
    return db

And then have:

import pytest
from mymodels import MyItem
from flask import url_for

@pytest.mark.usefixtures('client_class')
class TestMyApp:
    def test_delete(self, db_session, uid):
        item = MyItem(
            name='x'
        )
        db_session.add(item)
        db_session.commit()
        res = self.client.delete(url_for('myapi.ItemResource', id=item.id))
        assert res.status_code == 200

When i run the test, it always fails with a 404 error saying that the provided ID does not exist

@AbdealiLoKo
Copy link
Author

AbdealiLoKo commented Jul 3, 2019

Weirdly, when I do:

import pytest
from mymodels import MyItem
from flask import url_for

@pytest.mark.usefixtures('client_class')
class TestMyApp:
    def test_add(self, db_session, uid):
        res = self.client.post(url_for('myapi.ItemResource', name='x'))
        assert res.status_code == 200

        item_id = res.json['result']['id']
        item = db_session.query(MyItem).filter_by(id=item_id).one()
        db_session.delete(item)
        db_session.flush()
        with pytest.raises(NoResultFound):
            db_session.query(MyItem).filter_by(id=item_id).one()

it seems to work. indicating that things I create with client() is available in db_session

@jeancochrane
Copy link
Owner

Hm, that's pretty weird. From a quick scan, I can't see anything in your config that looks obviously wrong. Out of curiousity, would it be relatively simple to run the tests against Postgres instead of Sqlite? I haven't tested the plugin against Sqlite before and I'm wondering if there's something about the implementation of nested transactions that's interfering with your tests (some evidence that may be true here). If a quick port to Postgres is too strenuous, I'll try a simple replication of your case in Sqlite and see if I can reproduce the error.

@jeancochrane
Copy link
Owner

Another question: Do you see similar errors when you run updates against records, or only when you create them with the model ORM (as it looks like is happening in test_delete)? And can you post some code for MyModel?

@matt-takumi
Copy link

matt-takumi commented Dec 30, 2022

I have a similar issue to this, and I tracked it down to the session used in my app is different to the session that's used in my tests. I setup SQLAlchemy in my app like so:

src/takumi/extensions.py:


def configure_flask_sqlalchemy(app):
    db.init_app(app)
    Migrate(app, db)
    sqlalchemy.orm.configure_mappers()

src/takumi/app.py:


def create_app():
    app = Flask()
    ...
    configure_flask_sqlalchemy(app)

then src/takumi/application.py:


app = create_app()

We access the session and create models in our code like so:


class FooBar(db.Model):
    ...

db.query(FooBar).filter(...)
# or
FooBar.query.filter(...)

It occurred to me that perhaps it's something to do with instantiating the db object before the app is created, and it being a global, but I would be guessing! Happy to help debug further.

We're using PostgreSQL. I also had the following in our setup.cfg:

mocked-sessions=takumi.extensions.db.session
mocked-engines=takumi.extensions.db.engine

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