为了更快地进行测试,最好使用基于内存的sqlite,但仍需要偶尔使用MySQL进行测试,使其更接近于生产环境。 为了避免枯燥的讨论/抽象性问题,对于上面提到的两种类型的SQL数据库,下面的代码都会插入几个单词并确认它们已在数据库中。
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import unittest
db = SQLAlchemy()
TEST_DATABASE_URL_MEMORY = 'sqlite:///:memory:'
TEST_DATABASE_URL_MYSQL = 'mysql+pymysql://root:@127.0.0.1:3306/somewords'
def create_app(db_url):
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = db_url
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db.init_app(app)
return app
class Word(db.Model):
__tablename__ = 'words'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
word = db.Column(db.String(32), index=True)
class TestInsertion(unittest.TestCase):
def manual_set_up(self, db_url):
self.app = create_app(db_url)
self.app_context = self.app.app_context()
self.app_context.push()
db.drop_all()
db.create_all()
def insert(self):
words = ['hello', 'world']
for word in words:
w = Word(word=word)
db.session.add(w)
db.session.commit()
for word in words:
assert Word.query.filter_by(word=word).first() is not None
def test_dbs(self):
for db_url in [TEST_DATABASE_URL_MEMORY,
TEST_DATABASE_URL_MYSQL]:
self.manual_set_up(db_url)
self.insert()
第一个(sqlite)通过。第二个失败:
E sqlalchemy.exc.InternalError: (pymysql.err.InternalError) (1049, "Unknown database 'somewords'")
我们可以在每次运行测试时创建数据库
> mysql -u root -p
Welcome to the MySQL monitor. Commands end with ; or \g.
mysql> create database somewords;
Query OK, 1 row affected (0.02 sec)
mysql> quit;
但是这排除了自动化测试的可能,所以我想我缺少一些基本的知识。
如何通过自动创建数据库来自动执行上述测试?
更新
1.0,1.1的测试示例和教程(flask/examples/tutorial/tests/conftest.py
)使用tempfile.mkstemp()
,这似乎是一种不错的选择。无需担心设置名称和创建数据库,也不必担心(随机且可丢弃的)数据库名称。数据库创建部分如何/在哪里完成?
import tempfile
db_fd, db_path = tempfile.mkstemp()
答案 0 :(得分:3)
通过对manual_set_up
和test_dbs
进行一些修改,我可以运行代码。
对于mysql数据库,我从db_url
中删除了数据库名称。并且db.drop_all()
也会失败,因为该数据库不存在,所以我放入了try / except并在此处传递异常。然后在db.create_all()
之前,我绕过db_url
创建了一个没有数据库名称db.create_engine(db_url)
的sqlachemy引擎。
# your imports ...
import sqlalchemy.exc
#...
TEST_DATABASE_URL_MYSQL = 'mysql+pymysql://root:@127.0.0.1:3306/'
def manual_set_up(self, db_url, db_kind, db_name=None):
if db_kind == "mysql":
self.app = create_app(db_url + db_name)
else:
self.app = create_app(db_url)
self.app_context = self.app.app_context()
self.app_context.push()
try:
db.drop_all()
except sqlalchemy.exc.InternalError as e:
if "unknown database" in str(e.args[0]).lower():
pass
try:
db.create_all()
except sqlalchemy.exc.InternalError as e:
if "unknown database" in str(e.args[0]).lower():
db.create_engine(db_url, {}).execute(f"CREATE DATABASE IF NOT EXISTS {db_name};")
db.create_all()
def test_dbs(self):
for args in [(TEST_DATABASE_URL_MEMORY, "sqlite"),
(TEST_DATABASE_URL_MYSQL, "mysql", "somewords")]:
self.manual_set_up(*args)
self.insert()
答案 1 :(得分:1)
sqlalchemy似乎不直接支持创建和删除数据库,但是sqlalchemy-utils:https://sqlalchemy-utils.readthedocs.io/en/latest/_modules/sqlalchemy_utils/functions/database.html#create_database支持它。
这将需要您已经在运行mysql服务器,因此它不允许您使用tempfile.mkstemp()控制文件的位置。
另一种方法是在自动化测试中运行mysql
命令。