Question

I am developing my first Flask app. It is my side project, so I focus on good practises and design and take my time. I am a bit stuck on testing - I found some examples in docs and here on SO, but they either do not apply to my app or do not seem Pythonic/well designed.

The relevant pieces of code are:

# application module __init__.py
def create_app(config):
    app = Flask(__name__)
    app.config.from_object('config.%s' % config.title())
    return app  

config = os.getenv('CONFIG', 'development')
app = create_app(config)
db = SQLAlchemy(app)

# config.py
class Testing(Base):
    TESTING = True
    SQLALCHEMY_DATABASE_URI = \
        'sqlite:///' + os.path.join(_basedir, 'testing.sqlite')

# models.py
class User(db.Model):
    __tablename__ = 'user'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(60), unique=True, nullable=False)
    password_hash = db.Column(db.String(60), nullable=False)

# testing.py
class TestCase(unittest.TestCase):
    
    def setUp(self):
        self.app = create_app('testing')
        # TODO: create connection to testing db

    def tearDown(self):
        # TODO: abort transaction
        pass

The question is: how to implement setUp and tearDown so that in my tests I can use my models and connection do testing database? If I just import db, it would work on development database.

If it helps anything, I do not need to create testing db from scratch, I use Flask-Migrate and tests can assume the testing db is initialized and empty.

Any comments are welcome, I do not mind refactoring if my design is flawed.

Was it helpful?

Solution

It looks like you should just be able to run CONFIG=Testing python -m unittest discover and have everything just work. The only think you may want to change is, instead of calling create_app in your tests, simply import it from __init__.py:

# testing.py
from . import config, db

class TestCase(unittest.TestCase):

    def setUp(self):
        self.app = create_app(config)
        # db is properly set up to use the testing config
        # but any *changes* you make to the db object
        # (e. g. monkey-patching) will persist between tests
        db.create_all()

    def tearDown(self):
        db.session.remove()
        db.drop_all()

See here for an example.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top