Here are some tips when testing Flask/SQLAlchemy apps against MySQL.
General
- Use an application factory
- Separate configuration for testing and development.
- "configuration inheritance" with
import
- Separate test database
- Test database should be at the same revision as development
- Use alembic and flask-migrate
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()
, justsession.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