Flask unit test uses/accesses development databse even after creating a temporary database to test

58 Views Asked by At

I have created a flask App and this is the app.py file

from flask_migrate import Migrate
from dotenv import load_dotenv
import os
from src.app import create_app, db


load_dotenv()

app = create_app()

Migrate(app, db)

if __name__ == '__main__':
    app.run()

Now there is another app.py file inside the src folder where the function create_app is defined

from flask import Flask
from flask_restx import Api
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from dotenv import load_dotenv
import os


load_dotenv()

db = SQLAlchemy()
api = Api(prefix="/api")

def register_extensions(app):
    db.init_app(app)
    api.init_app(app)
    with app.app_context():
        db.create_all()


def register_blueprints(app):
    from src.apis import register_urls
    for route in register_urls.URL_CONFIG.urls:
        api.add_resource(route.view, route.get_url_prefix())

def configure_databse(app):
    @app.teardown_request
    def shutdown_session(exception=None):
        db.session.remove()

db_name = os.environ.get('DB_NAME')
db_user = os.environ.get('DB_USERNAME')
db_pass = os.environ.get('DB_PASSWORD')
db_port = os.environ.get('DB_PORT')
db_host = os.environ.get('DB_HOST')

def create_app():
    app = Flask(__name__)
    app.config['SQLALCHEMY_DATABASE_URI'] = f'mysql+pymysql://{db_user}:{db_pass}@{db_host}:{db_port}/{db_name}'
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    app.config['DEBUG'] = True
    register_extensions(app)
    from src.apis import register_models
    register_blueprints(app)
    configure_databse(app)
    return app

Now inside the tests folder I have created a common folder and a file named conftest.py

import unittest
from app import app as _app
from src.app import db as _db
import json

class BaseTest(unittest.TestCase):
    @classmethod
    def setUp(cls) -> None:
        with _app.app_context():
            _app.config['SQLALCHEMY_DATABASE_URI'] = "sqlite:///:memory:"
            _db.drop_all()
            _db.create_all()
            cls.client = _app.test_client()

now even after specifying the "sqlite:///:memory:" when I print(_db) I get the output as f'mysql+pymysql://{db_user}:{db_pass}@{db_host}:{db_port}/{db_name}'

and whenever I run the test cases there are changes observed in the development db.

What am I doing wrong here?

1

There are 1 best solutions below

0
Danila Ganchar On

The easiest way is just prepare env variables before run tests. Here is an example:

app.py:

import os

from flask import Flask


def create_app():
    _app = Flask(__name__)
    # let's say we have some settings
    _app.config['MODE'] = os.environ.get('MODE') or 'PRODUCTION'
    _app.config['TESTING'] = bool(os.environ.get('TESTING'))  # default = False
    # configure_database(_app)
    # blablabla...
    return _app


app = create_app()

test.py:

from unittest import TestCase

from app import app


class ExampleTest(TestCase):
    def test_config(self):
        self.assertEqual(app.config['MODE'], 'TEST')
        self.assertTrue(app.config['TESTING'])

Override settings and run test export MODE=TEST TESTING=1 && python -m unittest test:

.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

Or you can generate .env.tests config and load all variables before tests:

source .env.tests && python -m unittest test