首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在烧瓶测试中没有正确地移除sqlalchemy会话

在烧瓶测试中没有正确地移除sqlalchemy会话
EN

Stack Overflow用户
提问于 2013-10-16 05:11:09
回答 3查看 5.1K关注 0票数 7

我用的是烧瓶试验,它说:

另一个问题是,Flask也会在每个请求的末尾删除会话实例(与使用SQLAlchemy和scoped_session的任何线程安全应用程序一样)。因此,每次调用client.get()或其他客户端方法时,会话以及添加到它的任何对象都会被清除。

不过,我看不出来。此测试失败:

代码语言:javascript
复制
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.testing import TestCase

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy(app)
@app.route('/')
def index():
  print 'before request:', `db.session`
  u = db.session.query(User).first()
  u.name = 'bob'
  return ''

class User(db.Model):
  id = db.Column(db.Integer, primary_key=True)
  name = db.Column(db.String)

class SessionTest(TestCase):

  def create_app(self):
    return app

  def test_remove(self):
    db.drop_all()
    db.create_all()

    u = User()
    u.name = 'joe'
    db.session.add(u)
    db.session.commit()
    client = app.test_client()
    client.get('/')
    print 'after request:', `db.session`
    print u.name
    assert u not in db.session

(与$ nosetests test_file.py一起运行以查看它的运行情况。)

标准:

代码语言:javascript
复制
-------------------- >> begin captured stdout << ---------------------
before request: <sqlalchemy.orm.scoping.ScopedSession object at 0x10224c610>
after request: <sqlalchemy.orm.scoping.ScopedSession object at 0x10224c610>
bob

--------------------- >> end captured stdout << ----------------------

根据文档,用户u不应该在get请求之后出现在会话中,但是它是!有人知道为什么会这样吗?

此外,u.namebob而不是joe,即使请求从未提交!(所以我确信这是同一次会议。)

为了记录在案,

代码语言:javascript
复制
$ pip freeze | grep Flask
Flask==0.10.1
Flask-Bcrypt==0.5.2
Flask-DebugToolbar==0.8.0
Flask-Failsafe==0.1
Flask-SQLAlchemy==0.16
Flask-Script==0.6.2
Flask-Testing==0.4
Flask-Uploads==0.1.3
Flask-WTF==0.8
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-10-20 02:10:29

我非常肯定,混淆来自于SQLAlchemy中的会话是限定作用域的事实,这意味着每个请求处理程序都创建和销毁自己的会话。

这是必要的,因为web服务器可以是多线程的,因此可以同时处理多个请求,每个请求处理不同的数据库会话。

因此,在请求上下文之外使用的会话可能与处理'/'路由的视图函数在结束时得到并销毁的会话不同。

更新:我仔细研究了一下,发现了这件事。

烧瓶-SQLAlchemy在app.teardown_appcontext上安装一个钩子,这里是它调用db.session.remove()的地方。

测试环境不能完全复制实际请求的环境,因为它不会推送/弹出应用程序上下文。因此,会话从未在请求结束时被移除。

另外,请记住,在调用before_requestafter_request时,也不会调用在client.get()中注册的函数。

您可以通过对测试的小更改来强制应用程序上下文推送和弹出:

代码语言:javascript
复制
def test_remove(self):
  db.drop_all()
  db.create_all()

  u = User()
  u.name = 'joe'
  db.session.add(u)
  db.session.commit()
  with app.app_context():
      client = app.test_client()
      client.get('/')
  print 'after request:', `db.session`
  print u.name
  assert u not in db.session

通过这一更改,测试通过了。

用于瓶测试的文档似乎是错误的,或者更可能是过时的。也许事情在某种程度上像他们所描述的那样起作用了,但对于当前的水瓶和瓶-SQLAlchemy版本来说,这是不准确的。

我希望这能帮到你!

票数 10
EN

Stack Overflow用户

发布于 2013-10-18 08:52:59

FlaskClient处理请求上下文,而Flask调用它是shutdown_sessionapp.teardown_appcontext上,因为Flask 0.9。这就是为什么在测试客户端调用之后什么都不会发生,因为flask.ext.testing.TestCase在测试的setUp之前就已经启动了应用程序上下文,并且在tearDown之后就会关闭。

票数 0
EN

Stack Overflow用户

发布于 2016-01-06 07:12:54

当我尝试使用烧瓶时,我也遇到了同样的问题--设法运行我的测试。在单独的线程中运行测试解决了这个问题。

代码语言:javascript
复制
import threading
# some code omited
runner = unittest.TextTestRunner(verbosity=2)
t = threading.Thread(target=runner.run, args=[test_suite])
t.start()
t.join()
# other code omited
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19395697

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档