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.
There are a few things you need to do to get this to work.
Set the missing environmental variables (like you already said).
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()