This Content is from Stack Overflow. Question asked by Oyugo Obonyo
I am building a flask application and I have used a ‘create_app’ factory function to create an instance of the application. The factory function is as follows:
from config import Config from flask import Flask from dotenv import load_dotenv from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate db = SQLAlchemy() migrate = Migrate(render_as_batch=True) def create_app(config_class: Config): load_dotenv() app = Flask(__name__) app.config.from_object(config_class) db.init_app(app) migrate.init_app(app, db) from app.auth import bp as auth_bp app.register_blueprint(auth_bp) return app
I am using this pattern because I intend to use different configurations across different instances of my application i.e development, testing and production instances. This functionality is implemented by creating a configuration class within a config.py file, storing the configurations as attributes within the configuration class and passing this class as an argument to the create_app() function. For example, an app to be used during development can be created as follows:
from app import create_app from config import DevelopmentConfig app = create_app(config_class=DevelopmentConfig) app.run(port=5500)
The following config classes exist within config.py:
import os class Config(object): SQLALCHEMY_TRACK_MODIFICATIONS = False TESTING = False class DevelopmentConfig(Config): DEBUG = True SQLALCHEMY_DATABASE_URI = os.environ.get("DATABASE_URL") class TestingConfig(Config): SQLALCHEMY_DATABASE_URI = os.environ.get("TEST_DATABASE_URL") TESTING = True
While building my app’s test_suite, I have created a different app instance for testing as follows:
from app import create_app from config import TestingConfig import pytest @pytest.fixture(scope="session") def app(): app = create_app(config_class=TestingConfig) return app
I have created a different testing instance because I intend to separate resources I use for testing from those I use for development, most notably the database.
To confirm that the resources are indeed separated, I have written a test to confirm my testing instance’s configurations:
import os def test_app_configurations(app): assert app.config["TESTING"] is True assert app.config["SQLALCHEMY_DATABASE_URI"] == os.environ.get("TEST_DATABASE_URL")
This test however fails and I am hit with the following assertion error:
def test_app_configurations(app): assert app.config["TESTING"] is True > assert app.config["SQLALCHEMY_DATABASE_URI"] == os.environ.get("TEST_DATABASE_URL") E AssertionError: assert None == 'postgresql://test_user:password@localhost:5432/test_db'
To make this test pass, I have to explicitly declare my database URL in my app fixture after the create_app() function as follows:
@pytest.fixture(scope="session") def app(): app = create_app(config_class=TestingConfig) app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("TEST_DATABASE_URL") return app
I am however a bit confused. When running a development instance of the application, the attributes declared in the DevelopmentConfig class are automatically attached to the development instance. Why is that not the case for the testing instance. Why do I have to explicitly re-declare what I have already declared in the TestConfig class attributes? Is there something else I can do to make the test pass without having to reassign instances during testing when I already assigned the as class attributes in the TestConfig?
This question is not yet answered, be the first one who answer using the comment. Later the confirmed answer will be published as the solution.
This Question and Answer are collected from stackoverflow and tested by JTuto community, is licensed under the terms of CC BY-SA 2.5. - CC BY-SA 3.0. - CC BY-SA 4.0.