Flask-SQLAlchemy+MariaDB数据库Mock:库未创建时create_all报错的解决方法
解决Flask+unittest测试MariaDB时数据库不存在的问题
因为MariaDB是服务器型数据库,不像SQLite会自动创建数据库文件,所以必须先手动创建测试数据库,再操作表。可以通过以下步骤实现:
核心思路
- 在
setUp()中,先连接到MariaDB的默认系统数据库(比如mysql),执行创建测试数据库的SQL语句。 - 再调用
db.create_all()创建业务表。 - 在
tearDown()中,先删除业务表,再删除测试数据库。
具体实现代码
修改测试类,拆分数据库连接信息并手动管理测试库的创建/删除:
import unittest from sqlalchemy import create_engine from flask import current_app from app import create_app, db class BasicsTestCase(unittest.TestCase): def setUp(self): self.app = create_app('testing') self.app_context = self.app.app_context() self.app_context.push() # 从配置中拆分数据库连接信息 db_uri = self.app.config['SQLALCHEMY_DATABASE_URI'] split_uri = db_uri.split('/') test_db_name = split_uri[-1].split('?')[0] # 构建连接系统数据库(mysql)的URI system_db_uri = '/'.join(split_uri[:-1]) + '/mysql' if '?' in split_uri[-1]: system_db_uri += '?' + split_uri[-1].split('?')[1] # 连接系统库,创建测试数据库 system_engine = create_engine(system_db_uri) with system_engine.connect() as conn: conn.execution_options(isolation_level="AUTOCOMMIT") conn.execute(f"CREATE DATABASE IF NOT EXISTS {test_db_name}") # 现在可以正常创建业务表 db.create_all() def tearDown(self): db.session.remove() db.drop_all() # 连接系统库,删除测试数据库 db_uri = self.app.config['SQLALCHEMY_DATABASE_URI'] split_uri = db_uri.split('/') test_db_name = split_uri[-1].split('?')[0] system_db_uri = '/'.join(split_uri[:-1]) + '/mysql' if '?' in split_uri[-1]: system_db_uri += '?' + split_uri[-1].split('?')[1] system_engine = create_engine(system_db_uri) with system_engine.connect() as conn: conn.execution_options(isolation_level="AUTOCOMMIT") conn.execute(f"DROP DATABASE IF EXISTS {test_db_name}") self.app_context.pop()
关键说明
- 确保使用的数据库账号(比如示例中的
admin)拥有创建、删除数据库的权限。 - 添加
IF NOT EXISTS和IF EXISTS避免重复操作的报错。 - 设置
isolation_level="AUTOCOMMIT"是因为创建/删除数据库的语句无法在事务中执行,需要立即生效。
进阶替代方案
如果想完全隔离测试环境,不用手动管理数据库生命周期,可以使用Testcontainers库:它会在测试启动时自动拉起临时的MariaDB容器,测试结束后自动销毁容器,适合复杂测试场景,不过需要额外安装依赖。
内容的提问来源于stack exchange,提问作者AKA_Tom
相关产品推荐
相关产品推荐

