【问题标题】:Flask view testing: How do I prevent data from being saved to the database?Flask 视图测试:如何防止数据被保存到数据库中?
【发布时间】:2016-04-02 04:50:19
【问题描述】:

我有一个使用 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_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_client() 的替代方法?我不能直接调用该方法,因为jsonify 不允许我在响应之外的任何地方返回数据。

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

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

现在我不需要在我的测试中使用 jsonify()

【问题讨论】:

  • 您可以调用db.session.delete(object) 作为测试用例清理的一部分。或者调用 session.rollback() 应该恢复任何尚未提交的事务更改。
  • 我实际上在我的 setUp() 和 tearDown() 上都做了一个 rollback() 以防万一。我可以执行 delete(),但我不希望跟踪创建的每个对象然后再删除它。
  • 替代方法是覆盖 SQLAlchemy 配置以使用单独的数据库进行测试。在单元测试中查看Miguel Grinberg's Flask Megatutorial。在他的测试用例设置中,他更改了 SQLAlchemy URI 以使用 SQLite 测试数据库。当然,如果您尝试测试 psql,那将无法达到目的,但这样您就不必担心测试会留在生产数据库中。
  • 我确实使用单独的数据库进行测试。不幸的是,我正在测试我在原始 SQL 中所做的某些事情,即一旦创建了用户(在单独的应用程序上 - 这是“管理员”应用程序),通过触发器创建该用户的配置文件。所以使用db.create_all()db._drop_all() 并不能涵盖我的所有内容。实际上,我使我的测试数据库的迁移与我的主数据库保持同步
  • 在事务开始之前调用session.begin() 有影响吗?如果您已将 SQLAlchemy 配置为将 autocommit 设置为 True(不是默认值),则对 flush() 的调用也可能会提交事务,但在这一点上很难理解文档。更多信息herehere。我不知道,但你可以试试。

标签: python flask flask-sqlalchemy flask-testing


【解决方案1】:

test_clientflushrollback 一起使用是正确的方法。你对 jsonify 有什么顾虑?我没有看到与您的主要问题的联系。

也许您的拆卸回滚没有按您的意愿调用。包含内联回滚可让您在测试中验证状态是否清晰。

这里有一个要点表明这种方法有效。 https://gist.github.com/bhtucker/58a90e59265a0994bf42a23921d69718

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

【讨论】:

  • 正在运行回滚(我通过将其内联进行了双重检查 - 数据仍在保存中)并且我只显式调用刷新,从不提交。当我通过test_client 发出请求时,在幕后调用了提交,我通过覆盖提交和查询数据库来验证这一点,同时通过 ipdb 逐步完成测试。一旦数据库可以查询它,rollback() 就不会删除任何内容。我对 jsonify 的不满是因为我宁愿只测试视图方法本身,这很容易解决我的问题。
  • 我可以稍后再检查,但到目前为止回滚并没有解决我的问题
  • 在提交之前,信息只在同一个事务中可见。 db.session.add 正在启动一个事务,视图的查询也从这个事务内部运行(参见要点)。对我来说,更令人不安的是,您在通过test_client 请求期间看到了提交!这不正常
  • 我同意这不正常,但是我在测试开始时(在声明 db 的同一文件/范围内)通过 db.session.commit = lambda *args, **kwargs 对其进行了测试,并且没有其他更改数据不再被保存(但当test_client 提出一个请求时它正在回滚,我仍然不想要)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多