MPA
MPA

Reputation: 2038

How to correctly use pytest with Flask and SQLAlchemy

I am trying to create a pytest suite for my Flask app. To get myself started, I followed several tutorials, notably this, this, this, and this. Now, roughly 5 hours later, I am utterly defeated by the following message:

RuntimeError: The current Flask app is not registered with this 'SQLAlchemy' instance. Did you forget to call 'init_app', or did you create multiple 'SQLAlchemy' instances?

Here is what I did. I created a tests/conftest.py file with the following contents:

import pytest
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

class Config:
    SQLALCHEMY_DATABASE_URI = "sqlite:///:memory:"
    TESTING = True

@pytest.fixture(scope="session")
def app(config_class=Config):
    app = Flask(__name__)
    app.config.from_object(config_class)

    db = SQLAlchemy()
    db.init_app(app)

    with app.app_context():
        db.create_all()
        yield app
        db.session.close()
        db.drop_all()

Then, I created a test file called tests/test_db.py:

from app.models import User

def test_init(app):
    with app.app_context():
        id = "0"
        user_query = User.query.filter_by(id=id).first()

I've tried about 573 variations with and without app_context, moving the database init to a separate fixture, using pytest-flask-sqlalchemy, creating clients, app_context().push(), etc. etc. No matter what I do, I either get the The current Flask app is not registered message, or A 'SQLAlchemy' instance has already been registered on this Flask app. Import and use that instance instead.

For good measure, I asked ChatGPT for a working solution, and repeated that request a few times over to try each of its equally non-functioning solutions. But that was to be expected...

So. Could anyone give me an actually working example of how to use pytest with Flask and SQLAlchemy?

Upvotes: 1

Views: 77

Answers (1)

ViAchKoN
ViAchKoN

Reputation: 724

Maybe it is something with how you set up a test client. From the first glance it looks okay. I did something similar but used a postgres database for testing.

# a single method to create app for both testing and running
def create_app():
   app = Flask(
        __name__,
   )
   app.config.from_object(config_class)
   db.init_app(app) # <- this db is the same which you are using in the main app
   Migrate(app, db)

   # register endpoints
   # app.register_blueprint(some_blp)

   return app


@pytest.fixture(scope="session")
def app():
    test_app = construct_app(app)

    with test_app.test_client() as cl:
        with test_app.app_context():
            db.create_all()
        yield cl
        with test_app.app_context():
            db.session.commit()
            db.drop_all()

This setup should work.

You can check my pet project (repo) which I did in the past where I also wrote tests. It was one of the first projects I had written on flask so there things I would do differently.

Upvotes: 0

Related Questions