我开始使用TDD开发Flask应用。
生产代码和测试都使用带有SQlite的通用SQLAlchemy实例,以实现可重用性。
在__init __。py 中:
db = SQLAlchemy()
因此,测试和实际应用程序都需要访问该数据库实例,但是具有不同的配置:tests.py使用/ tmp /文件来创建虚拟数据。
因此,关于Flask_SQLAlchemy文档,每次使用'db'时,我都会调用正确的应用上下文。
结构:
tests.py
run.py
application/
__init__.py
config.py
models.py
views.py
这是一些关键代码:
__ init.py __ :
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
from application.models import *
def create_app(conf_object):
app = Flask(__name__)
app.config.from_object(conf_object)
db.init_app(app)
return (app, db)
tests.py :
from flask_sqlalchemy import SQLAlchemy
from application import create_app
import unittest
import os
app, db = create_app('application.config.TestConf') # Test conf: db file will bt a tempfile
from application.models import Update, Update_State, Device, Confirmation
db.create_all(app=app) # Create tables with app context
class APITestCase(unittest.TestCase):
def setUp(self):
"""Sets up a hardcoded dummy-data database before each test"""
# Hardcoded fake database
d1 = Device('1223456789', 'hub', 'R3pTkEAHyUKbUJW7bSK8k5')
d2 = Device('AZERTY', 'hub', 'R3pTkEAHyUKbUJW7bSK8k5')
db.session.add(d1)
db.session.add(d2)
db.session.commit()
self.app = app.test_client()
def tearDown(self):
"""Destroy fake db after each test"""
os.close(app.config['DB_FD'])
os.unlink(app.config['DB_FILE'])
# assert functions
def test_confirmation_msg_correct(self):
tester = app.test_client(self)
response = tester.get('/confirmation-msg', query_string=dict(deviceid='1223456789', updateid='R3pTkEAHyUKbUJW7bSK8k5'), content_type='html/text')
self.assertEqual(response.status_code, 200)
if __name__ == '__main__':
with app.app_context(): # Because using using a generic SQLAlchemy() 'db' instance, we need to specify the app. See Flask_sqlalchemy doc, 'Introduction into contexts'
unittest.main()
models.py :
from application import db
import datetime
import shortuuid
class Device(db.Model):
id = db.Column(db.String(255), primary_key=True)
type = db.Column(db.String(255))
version_id = db.Column(db.String(511))
def __init__(self, id, type, version_id):
self.id = id
self.type = type
self.version_id = version_id
还有其他一些模型,但我将其简单说明。
问题出在 setUp(self)函数中,该函数将伪数据添加到数据库中。即使导入了模型并且代码已在正确的应用程序上下文中执行,引擎也找不到表。
没有这样的表格:设备
sqlalchemy.exc.InvalidRequestError: This Session's transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: (sqlite3.OperationalError) no such table: device [SQL: 'INSERT INTO device (id, type, version_id) VALUES (?, ?, ?)'] [parameters: (('1223456789', 'hub', 'R3pTkEAHyUKbUJW7bSK8k5'), ('AZERTY', 'hub', 'R3pTkEAHyUKbUJW7bSK8k5'))] (Background on this error at: http://sqlalche.me/e/e3q8)
此外,设置 SQLALCHEMY_ECHO = True 时,显然使用db.create_all(app = app)可以很好地创建表:
2018-07-31 17:06:45,333 INFO sqlalchemy.engine.base.Engine SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1
2018-07-31 17:06:45,333 INFO sqlalchemy.engine.base.Engine ()
2018-07-31 17:06:45,334 INFO sqlalchemy.engine.base.Engine SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1
2018-07-31 17:06:45,334 INFO sqlalchemy.engine.base.Engine ()
2018-07-31 17:06:45,334 INFO sqlalchemy.engine.base.Engine PRAGMA table_info("update__state")
2018-07-31 17:06:45,334 INFO sqlalchemy.engine.base.Engine ()
2018-07-31 17:06:45,335 INFO sqlalchemy.engine.base.Engine PRAGMA table_info("device")
2018-07-31 17:06:45,335 INFO sqlalchemy.engine.base.Engine ()
2018-07-31 17:06:45,335 INFO sqlalchemy.engine.base.Engine PRAGMA table_info("confirmation")
2018-07-31 17:06:45,335 INFO sqlalchemy.engine.base.Engine ()
2018-07-31 17:06:45,335 INFO sqlalchemy.engine.base.Engine PRAGMA table_info("update")
2018-07-31 17:06:45,336 INFO sqlalchemy.engine.base.Engine ()
2018-07-31 17:06:45,336 INFO sqlalchemy.engine.base.Engine
CREATE TABLE "update" (
update_id VARCHAR(511) NOT NULL,
version VARCHAR(255),
description VARCHAR(2047),
date_created DATETIME,
PRIMARY KEY (update_id)
)
2018-07-31 17:06:45,336 INFO sqlalchemy.engine.base.Engine ()
2018-07-31 17:06:45,349 INFO sqlalchemy.engine.base.Engine COMMIT
2018-07-31 17:06:45,350 INFO sqlalchemy.engine.base.Engine
CREATE TABLE update__state (
last_communicated_version_id VARCHAR(255) NOT NULL,
PRIMARY KEY (last_communicated_version_id),
FOREIGN KEY(last_communicated_version_id) REFERENCES "update" (update_id)
)
2018-07-31 17:06:45,350 INFO sqlalchemy.engine.base.Engine ()
2018-07-31 17:06:45,368 INFO sqlalchemy.engine.base.Engine COMMIT
2018-07-31 17:06:45,376 INFO sqlalchemy.engine.base.Engine
CREATE TABLE device (
id VARCHAR(255) NOT NULL,
type VARCHAR(255),
version_id VARCHAR(511) NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY(version_id) REFERENCES "update" (update_id)
)
2018-07-31 17:06:45,377 INFO sqlalchemy.engine.base.Engine ()
2018-07-31 17:06:45,387 INFO sqlalchemy.engine.base.Engine COMMIT
2018-07-31 17:06:45,388 INFO sqlalchemy.engine.base.Engine
CREATE TABLE confirmation (
id INTEGER NOT NULL,
device_id INTEGER,
version_id VARCHAR(511) NOT NULL,
timestamp DATETIME,
PRIMARY KEY (id),
UNIQUE (device_id),
FOREIGN KEY(device_id) REFERENCES device (id),
FOREIGN KEY(version_id) REFERENCES "update" (update_id)
)
希望我很清楚,谢谢。
答案 0 :(得分:0)
已解决:
应用程序无法写入tempfile.mkstemp()在/ tmp中创建的数据库文件。 使用相对的本地路径,它可以工作。