当我运行测试时它成功连接到数据库,但它没有创建表。我想当我使用 flask-sqlalchemy 时可能有不同的创建表的方法,但我找不到解决方案。
这是app.py
db = SQLAlchemy()
def create_app(config_name):
app = Flask(__name__, template_folder='templates')
app.wsgi_app = ProxyFix(app.wsgi_app)
app.config.from_object(config_name)
app.register_blueprint(api)
db.init_app(app)
@app.route('/ping')
def health_check():
return jsonify(dict(ok='ok'))
@app.errorhandler(404)
def ignore_error(err):
return jsonify()
app.add_url_rule('/urls', view_func=Shorty.as_view('urls'))
return app
这是run.py
environment = environ['TINY_ENV']
config = config_by_name[environment]
app = create_app(config)
if __name__ == '__main__':
app.run()
这是config.py
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config:
"""
set Flask configuration vars
"""
# General config
DEBUG = True
TESTING = False
# Database
SECRET_KEY = os.environ.get('SECRET_KEY', 'my_precious_secret_key')
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root@localhost:3306/tiny'
SQLALCHEMY_TRACK_MODIFICATIONS = False
SERVER_HOST = 'localhost'
SERVER_PORT = '5000'
class TestConfig(Config):
"""
config for test
"""
TESTING = True
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root@localhost:3306/test_tiny'
config_by_name = dict(
test=TestConfig,
local=Config
)
key = Config.SECRET_KEY
这是模型.py
from datetime import datetime
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class URLS(db.Model):
__tablename__ = 'urls'
id = db.Column(db.Integer, primary_key=True)
original_url = db.Column(db.String(400), nullable=False)
short_url = db.Column(db.String(200), nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow()
这是测试配置设置。
db = SQLAlchemy()
@pytest.fixture(scope='session')
def app():
test_config = config_by_name['test']
app = create_app(test_config)
app.app_context().push()
return app
@pytest.fixture(scope='session')
def client(app):
return app.test_client()
@pytest.fixture(scope='session')
def init_db(app):
db.init_app(app)
db.create_all()
yield db
db.drop_all()
最佳答案
以下可能是阻止您的代码多次运行和/或阻止您删除/创建表的问题。不管它是否解决了您的问题,人们可能都没有意识到这一点,但要牢记这一点非常重要。 :)
当您多次运行测试时,db.drop_all()
可能不会被调用(因为您的一个测试失败了),因此,它可能无法在下次运行(因为它们已经存在)。问题在于使用没有 try:finally:
的上下文管理器。 (注意:每个使用 yield
的 fixture 都是上下文管理器)。
from contextlib import contextmanager
def test_foo(db):
print('begin foo')
raise RuntimeError()
print('end foo')
@contextmanager
def get_db():
print('before')
yield 'DB object'
print('after')
此代码代表您的代码,但不使用 pytest 的功能。 Pytest 或多或少像在运行它
try:
with get_db(app) as db:
test_foo(db)
except Exception as e:
print('Test failed')
人们期望的输出类似于:
before
begin_foo
after
Test failed
但我们只得到
before
begin_foo
Test failed
当上下文管理器处于事件状态时(yield
已执行),我们的测试方法正在运行。如果在执行我们的测试函数期间引发异常,则执行将停止,而不会在 yield
语句之后运行任何代码。为了防止这种情况,我们必须将 fixture
/contextmanager
包装在 try: ... finally:
block 中。作为finally无论发生什么,总是执行。
@contextmanager
def get_db():
print('before')
try:
yield 'DB object'
finally:
print('after')
yield
语句之后的代码现在按预期执行。
before
begin foo
after
Test failed
如果您想了解更多信息,请参阅 contextmanager docs 中的相关部分:
At the point where the generator yields, the block nested in the with statement is executed. The generator is then resumed after the block is exited. If an unhandled exception occurs in the block, it is reraised inside the generator at the point where the yield occurred. Thus, you can use a try…except…finally statement to trap the error (if any), or ensure that some cleanup takes place.
关于python - flask +Pytest+SQLAlchemy : Can't create and drop tables when run pytest using flask-sqlalchemy,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56939383/