Python 如何测试使用 SQLAlchemy 的 Flask 应用程序?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17791571/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I test a Flask application which uses SQLAlchemy?
提问by Ellochka Cannibal
I have a working web application on Flask with SqlAlchemy for moderation of news, it has some api methods to handle moderation requests, such as approve, deny currently selected news, list them, etc.
我在 Flask 上有一个使用 SqlAlchemy 进行新闻审核的 Web 应用程序,它有一些 api 方法来处理审核请求,例如批准、拒绝当前选择的新闻、列出它们等。
I want to write unit tests to this methods, and I made them work, but I don't understand how to implement executing all requests which I do from test cases in one db session, so that I could remove all changes to database. Or is there another cleaner or proper way to do this?
我想为这个方法编写单元测试,我让它们工作,但我不明白如何在一个数据库会话中执行我从测试用例执行的所有请求,以便我可以删除对数据库的所有更改。或者是否有另一种更清洁或正确的方法来做到这一点?
I've found out that maybe all I need is "scoped_session" in SqlAlchemy, but all my attempts to implement it have failed. If that's correct way, please, tell me where to use this lines of code (in settings, or in test case set_up method).
我发现也许我所需要的只是 SqlAlchemy 中的“scoped_session”,但是我实现它的所有尝试都失败了。如果这是正确的方法,请告诉我在哪里使用这行代码(在设置中,或在测试用例 set_up 方法中)。
from sqlalchemy.orm import scoped_session
from sqlalchemy.orm import sessionmaker
session_factory = sessionmaker()
Session = scoped_session(session_factory)
采纳答案by codegeek
I suggest you use the Flask-Testingextension. This is an approved extension which lets you do the unit testing as you desire. It has a specific section for SQLAlchemy as well.
我建议你使用Flask-Testing扩展。这是一个经过批准的扩展,可让您根据需要进行单元测试。它也有一个针对 SQLAlchemy 的特定部分。
Testing with SQLAlchemy
使用 SQLAlchemy 进行测试
This covers a couple of points if you are using Flask-Testing with SQLAlchemy. It is assumed that you are using the Flask-SQLAlchemy extension, but if not the examples should not be too difficult to adapt to your own particular setup.
如果您将 Flask-Testing 与 SQLAlchemy 一起使用,这将涵盖几点。假设您使用的是 Flask-SQLAlchemy 扩展,但如果不是,示例应该不会太难适应您自己的特定设置。
First, ensure you set the database URI to something other than your production database! Second, it's usually a good idea to create and drop your tables with each test run, to ensure clean tests:"
首先,确保将数据库 URI 设置为生产数据库以外的其他内容!其次,在每次测试运行时创建和删除表通常是一个好主意,以确保干净的测试:”
from flask.ext.testing import TestCase
from myapp import create_app, db
class MyTest(TestCase):
SQLALCHEMY_DATABASE_URI = "sqlite://"
TESTING = True
def create_app(self):
# pass in test configuration
return create_app(self)
def setUp(self):
db.create_all()
def tearDown(self):
db.session.remove()
db.drop_all()
回答by AlexLordThorsen
This is the way I've been running unit tests recently. I'm assuming since you are using SQLAlchemy that you're using model classes. I'm also assuming that all of your tables are defined as SQLAlchemy model classes.
这是我最近运行单元测试的方式。我假设因为您使用的是 SQLAlchemy,所以您使用的是模型类。我还假设您的所有表都定义为 SQLAlchemy 模型类。
from flask import Flask
import unittest
from app import db
from app.models import Log
from constants import test_logs
class appDBTests(unittest.TestCase):
def setUp(self):
"""
Creates a new database for the unit test to use
"""
self.app = Flask(__name__)
db.init_app(self.app)
with self.app.app_context():
db.create_all()
self.populate_db() # Your function that adds test data.
def tearDown(self):
"""
Ensures that the database is emptied for next unit test
"""
self.app = Flask(__name__)
db.init_app(self.app)
with self.app.app_context():
db.drop_all()
Since you're using the same DB set up as your app this allows you to build and destroy a test database with every unit test you run.
由于您使用的数据库设置与应用程序相同,因此您可以在运行的每个单元测试中构建和销毁测试数据库。
回答by user2659443
Regarding codegeek's answer using Flask-Testing, I have trouble understanding what createapp()
does. Flask-SqlAlchemy Introduction into Contextsprovided me some pointer on how to bind SQLAlchemy object dynamically to your application. In this case, binding to the test application.
关于使用 Flask-Testing 的 codegeek 的答案,我无法理解createapp()
它的作用。Flask-SqlAlchemy Introduction into Contexts为我提供了一些关于如何将 SQLAlchemy 对象动态绑定到您的应用程序的指针。在这种情况下,绑定到测试应用程序。
Basically:
基本上:
- Create a flask sqlalchemy object but do not pass in the app object
- In the create_app function, create your test application, and dynamically bind SQLAlchemy.
- 创建一个flask sqlalchemy对象但不传入app对象
- 在 create_app 函数中,创建您的测试应用程序,并动态绑定 SQLAlchemy。
Your myapp.py:
你的myapp.py:
# don't pass in the app object yet
db = SQLAlchemy()
def create_test_app():
app = Flask(__name__)
app.config['TESTING'] = True
app.config["SQLALCHEMY_DATABASE_URI"] = "xxxxxxtestdatabasexxx"
# Dynamically bind SQLAlchemy to application
db.init_app(app)
app.app_context().push() # this does the binding
return app
# you can create another app context here, say for production
def create_production_app():
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "xxxxxxproductionxxxx"
# Dynamically bind SQLAlchemy to application
db.init_app(app)
app.app_context().push()
return app
You can then follow codegeek's solution as outlined in Flask-Test Documentation
然后,您可以按照 Flask-Test 文档中概述的 codegeek 解决方案进行操作
from flask.ext.testing import TestCase
from myapp import create_app, db
class MyTest(TestCase):
# I removed some config passing here
def create_app(self):
return create_test_app()
def setUp(self):
db.create_all()
def tearDown(self):
db.session.remove()
db.drop_all()
The nice thing about this solution is that you can create different applications and dynamically bind the SQLAlchemy object using a function. Each application can serve different purposes. For example, one for production, and one for unit-test. In the case for production, you can call create_production_application() in your top level flask application.
这个解决方案的好处是您可以创建不同的应用程序并使用函数动态绑定 SQLAlchemy 对象。每个应用程序可以用于不同的目的。例如,一种用于生产,一种用于单元测试。在生产的情况下,您可以在顶级烧瓶应用程序中调用 create_production_application() 。