Here are some tips when testing Flask/SQLAlchemy apps against MySQL.

General

TestCase isolation

  • It is important to start each testcase with a clean database.
  • The classic approach is to wrap each testcase in a transaction and then rollback.
  • MySQL supports SAVEPOINTS. In sqlalchemy we can use begin_nested()
    See Using SAVEPOINT
  • The begin/rollback cycle is a perfect candidate for a context manager
  • do not session.commit(), just session.flush()
from contextlib import contextmanager


@contextmanager
def transaction_context(test_case):
    session = test_case.app.db.session
    try:
        session.begin_nested()
        yield session
    finally:
        session.rollback()
        session.close()
import unittest
from contextlib import contextmanager
from myapp.app import create_app


@contextmanager
def transaction_context(test_case):
    session = test_case.app.db.session
    try:
        session.begin_nested()
        yield session
    finally:
        session.rollback()
        session.close()


class TestCase(unittest.TestCase):

    def setUp(self):
        self.app = create_app(config="myapp.config_testing")
        self.app_context = self.app.app_context()
        self.app_context.push()
        self.app.testing = True
        self.test_app = self.app.test_client()
        self._savepoint_context = transaction_context(self)
        self._savepoint_context.__enter__()

    def tearDown(self):
        self._savepoint_context.__exit__(None, None, None)
        self.app_context.pop()
        self.app_context = None
        self.test_app = None
        self.app = None