Search code examples
testingflaskpeeweeflask-security

DB not changing when testing Flask-Security with peewe and PyTest


I just got into testing my flask application with pytest, and it mostly works as expected. Unfortunately the test uses the live DB instead a mock one. I'm quite sure this has to do with the fact, that flask-security is using peewee's database_wrapper instead of an "straightforward" database.

Here's some code. This is from the test:

@pytest.fixture
def client():
db_fd, belavoco_server.app.config['DATABASE']  = {  'name': 'userLogin_TEST.db',
                                                    'engine': 'peewee.SqliteDatabase' }                                                   }

belavoco_server.app.config['TESTING'] = True
client = belavoco_server.app.test_client()

#this seems not to help at all
with belavoco_server.app.app_context():
     belavoco_server.users.user_managment.db_wrapper.init_app(belavoco_server.app)

yield client

os.close(db_fd)
os.unlink(belavoco_server.app.config['DATABASE'])

This is some code from my bv_user_model.py

app.config['DATABASE'] = {
    'name': 'userLogin.db',
    'engine': 'peewee.SqliteDatabase',
}

app.config['SECURITY_URL_PREFIX'] = "/users"

# Create a database instance that will manage the connection and
# execute queries
db_wrapper = FlaskDB(app)

class Role(db_wrapper.Model, RoleMixin):
    name = CharField(unique=True, default="standard")
    description = TextField(null=True)

    def __repr__(self):
        return self.name

When preforming the test, Flask is using the userLogin.db instead of userLogin_TEST.db. I suppose this is because of the db_wrapper in bv_user_model.py - but I did not find a way to change this behaviour. Any help would be greatly appreciated!


Solution

  • The root of the issue seems to be this in bv_user_model:

    app.config['DATABASE'] = {
        'name': 'userLogin.db',
        'engine': 'peewee.SqliteDatabase',
    }
    

    Since you are using FlaskDB with the app that has the production credentials, it seems like the db_wrapper will "remember" that and not be overridden by your tests.

    The most straightforward answer would be to not use your app to create the FlaskDB instance directly

    db = FlaskDB()
    

    And then later on initialize it on your app

    from models import db
    def create_app():
        app = ...
        app.config["DATABASE"] = ...
        db.init_app(app)
        ...
        return app
    

    Which would let you have a separate function like this which you can use for testing.

    def create_test_app():
        app = ...
        app.config["DATABASE"] = ...test credentials...
        db.init_app(app)
        ...
        return app
    

    and when you create your models, use the FlaskDB instance just the same as you were already.

    db = FlaskDB()
    class Role(db.Model, RoleMixin):
        ...