Python Flask视图测试:如何防止数据保存到数据库?

Python Flask视图测试:如何防止数据保存到数据库?,python,flask,flask-sqlalchemy,flask-testing,Python,Flask,Flask Sqlalchemy,Flask Testing,我有一个带有SQLAlchemy的应用程序,已初始化: config_name = os.getenv('FLASK_CONFIG') or 'default' app = Flask(__name__) db = SQLAlchemy(app) db.init_app(app) 我正在处理的一个视图以json格式返回所有用户: @app.route('/users', methods=['GET']) def users(): users = db.session.query(Use

我有一个带有SQLAlchemy的应用程序,已初始化:

config_name = os.getenv('FLASK_CONFIG') or 'default'
app = Flask(__name__)
db = SQLAlchemy(app)
db.init_app(app)
我正在处理的一个视图以json格式返回所有用户:

@app.route('/users', methods=['GET'])
def users():
    users = db.session.query(User)

    output = {'users': [user.to_json() for user in users]}
    return jsonify(**output)
还有我的测试:

class UserViewTest(BaseTestCase, CreateUserMixin):
    def test_users(self):
        user1 = self._make_user() # defined in the above mixin
        user2 = self._make_user()
        user2.email = 'hello@abc.com'
        user2.username = 'hello@abc.com'
        db.session.add_all([user1, user2])
        db.session.flush()
        response = app.test_client().get('/users')
我使用
FLASK\u CONFIG=testing nosetests
运行测试(我选中了,app.testing设置为true)

对我的psql数据库运行此命令,我发现我添加到数据库中的这些用户正在被保存

triller_social_test=# SELECT username FROM users;
   username    
---------------
 foobar
 hello@abc.com
(2 rows)
我该如何阻止这种情况发生?我试图重写db.session.commit()以不执行任何操作,但在调用视图时数据库会回滚。除了使用
test\u client()
,还有其他选择吗?我不能直接调用该方法,因为
jsonify
不允许我在响应之外的任何地方返回数据

更新:以下是我的临时(?)解决方案:

def json_response_converter(dict_):
    if config_name == 'testing':
        return dict_
    else:
        return jsonify(**dict_)

现在我不需要在测试中使用jsonify(),使用
test\u client
flush
并使用
rollback
是正确的方法。你对jsonify有什么担心?我看不出与你的主要问题有什么联系

也许您的撕裂回滚没有按您希望的方式调用。包括在线回滚允许您在测试中验证状态是否清晰

这里有一个要点说明了这种方法的有效性


您应该能够在具有
psql
工具和适当的python依赖项的环境中简单地运行
bash setup\u和\u test.sh

您可以调用
db.session.delete(object)
,作为测试用例清理的一部分。或者调用
session.rollback()
应该还原所有尚未提交的事务更改。我实际上在setUp()和tearDown()上都执行了rollback(),以防万一。我可以执行delete(),但我不希望跟踪创建的每个对象然后将其删除。另一种方法是覆盖SQLAlchemy配置以使用单独的数据库进行测试。看看单元测试。在他的测试用例设置中,他将SQLAlchemy URI更改为使用SQLite测试数据库。当然,如果您试图测试psql,那就达不到目的,但这样您就不必担心测试会留在生产数据库中。实际上,我使用单独的数据库进行测试。不幸的是,我正在测试我在原始SQL中所做的某些事情,即一旦创建了一个用户(在一个单独的应用程序上——这是“admin”应用程序),该用户的配置文件就会通过触发器创建。所以使用
db.create\u all()
db.\u drop\u all()
对我来说并不能涵盖所有内容。实际上,我会使测试数据库的迁移与主数据库保持最新状态,在事务开始之前调用
session.begin()
是否会产生影响?如果您已将SQLAlchemy的autocommit设置为True(不是默认值),则对
flush()
的调用可能也会提交事务,但此时很难理解文档。更多信息和信息。我不知道,但你可以试试。回滚正在运行(我通过内联方式进行了双重检查-数据仍在保存),我只显式调用flush,从不提交。当我通过
test\u client
发出请求时,会在后台调用Commit,我通过覆盖Commit和通过ipdb单步执行测试时查询数据库来验证。一旦数据库可以查询它,rollback()就不会删除任何内容。我对jsonify的不满是因为我宁愿只测试view方法本身,这将很容易解决我的问题。我可以稍后再检查,但到目前为止rollback还没有解决我的问题。在提交之前,信息仅在同一事务中可见
db.session.add
正在启动一个事务,视图的查询也从该事务内部运行(参见要点)。对我来说,更令人不安的是,在通过
test\u客户机的请求过程中,您看到了提交!这不正常我同意这不正常,但当我的测试开始时(在声明db的同一文件/范围内),我只做了
db.session.commit=lambda*args,**kwargs
,并没有其他更改,数据就不再被保存(但是当
test\u客户端
发出一个请求时,它被回滚了,我仍然不想这样做)