hammygoonan February 2016

Flask-Script loads app before running unittests

I'm using Flask-Script to run tests on my application the important bit of my manage.py file looks like this:

import unittest

from flask.ext.script import Manager
from project import app

manager = Manager(app)

@manager.command
def test():
    """Run unit tests."""
    app.config.from_object('config.Test')
    tests = unittest.TestLoader().discover('tests', pattern='*.py')
    unittest.TextTestRunner(verbosity=1).run(tests)

But when I run python manage.py test it tries to initialise the entire application so if, for example, I haven't set my environment variables it throws a KeyError from my project's __init__.py file like so:

File "project/__init__.py", line 19, in <module> app.config.from_object(os.environ['PROJECT_SETTINGS'])

Or if I have set the environment variable I get an error about missing database tables.

Surely the app should only initialise once the tests are running and the configuration variables have been set in the test() function.

Answers


pech0rin February 2016

There are a few things you need to do to get this to work.

  1. Set the missing environmental variables (like you already said).

  2. Create a test database for your tests to use and have your tests include a setup and a teardown function that create the tables and remove them respectively.

To get around step one I suggest using the Flask application factory pattern which allows you to encapsulate your application creation inside a function. This will allow you to pass in whatever variables, etc are necessary to run your application under a test environment i.e.

def create_application(is_test=False):
    app = Flask(__name__)
    if not is_test:
       setup_app_not_for_test(app)
    else:
       setup_test_for_app(app)

    return app

In regards to step number 2, if you are using pytest or nose or any sort of testing framework that uses fixtures you can easily add setup and teardown functions to add/drop database tables. Additionally, if you are using an ORM like sqlalchemy you can create an SQLite in memory database very easily to run your tests against.

# create db instance
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite://:memory:"

# create all your tables
db.create_all()

# drop all your tables
db.drop_all()

Post Status

Asked in February 2016
Viewed 2,487 times
Voted 4
Answered 1 times

Search




Leave an answer