How do I mock PyMongo for testing with a Flask app?
we can wrap app
and mongo
in a functionThis works because mongo
is used as a local variable.
app.py
from flask import Flaskfrom flask_pymongo import PyMongodef get_app_with_config(config): app = Flask(__name__) app.config.from_object(config) mongo = PyMongo(app) @app.route("/") def index(): pass . . return app, mongo
then we can create a test file and an application execution file with different databases:
test_app.py
from app import get_app_with_configfrom config import TestConfigapp, mongo = get_app_with_config(TestConfig)
run.py
from app import get_app_with_configfrom config import RunConfigapp, mongo = get_app_with_config(RunConfig)if __name__ == '__main__': app.run(port=8000)
Sample of config.py file:
class RunConfig: MONGO_HOST = '192.168.1.37' MONGO_PORT = 27017 MONGO_DBNAME = 'my_database' MONGO_URI = f"mongodb://{MONGO_HOST}:{MONGO_PORT}/{MONGO_DBNAME}"class TestConfig: MONGO_HOST = '192.168.1.37' MONGO_PORT = 27017 MONGO_DBNAME = 'my_database_test' MONGO_URI = f"mongodb://{MONGO_HOST}:{MONGO_PORT}/{MONGO_DBNAME}" TESTING = True
Needed a quick fix so I edited app.py
so that it only hard-fails if PyMongo doesn't initialise when the file is executed (i.e. it ignores PyMongo's failed initialisation when running unit-tests.)
app = Flask(__name__)app.config["MONGO_DBNAME"] = os.environ.get('DB_NAME')app.config["MONGO_URI"] = os.environ.get('MONGO_URI')app.secret_key = os.environ.get('SECRET')try: mongodb = PyMongo(app).dbexcept ValueError: """We don't provide a URI when running unit tests, so PyMongo will fail to initialize. This is okay because we replace it with a version for testing anyway. """ print('PyMongo not initialized!') mongodb = None...if __name__ == '__main__': if not mongodb: print('Cannot run. PyMongo failed to initialize. Double check environment variables.') exit(1) app.run(host=os.environ.get('IP'), port=int(os.environ.get('PORT')), debug=False)
In my tests file, I just assign the mocked mongoDB client to the app in the tests that need it. Definitely not the ideal solution.
def test_redacted(client, mongodb): app.mongodb = mongodb ...