Flask + SQLAlchemy + pytest - 不回滚我的会话

时间:2015-11-21 20:18:59

标签: flask-sqlalchemy pytest

关于堆栈溢出有几个类似的问题,如果我通过询问另一个礼节来打破礼仪,我会提前道歉,但我似乎无法想出适当的咒语来使这项工作。< / p>

我尝试使用Flask + Flask-SQLAlchemy然后使用pytest来管理会话,这样当功能范围的pytest fixture被拆除时,当前的转换将被回滚。

其他一些问题似乎主张使用db&#34; drop all并创建所有&#34;函数范围内的pytest fixture,但我尝试使用连接会话,并使用回滚,因为我有很多测试。这会大大加快速度。

http://alexmic.net/flask-sqlalchemy-pytest/是我找到原始想法的地方,Isolating py.test DB sessions in Flask-SQLAlchemy是推荐使用功能级数据库重新创建的问题之一。

我也看过https://github.com/mitsuhiko/flask-sqlalchemy/pull/249,但似乎已经发布了flask-sqlalchemy 2.1(我正在使用)。

我现在的(非常小的,希望可以立即理解的)回购在这里: https://github.com/hoopes/flask-pytest-example

有两个打印语句 - 第一个(在示例/ __ init__.py中)应该有一个Account对象,第二个(在test / conftest.py中)是我希望在事务发生后清除db的地方回滚。

如果您pip install -r requirements.txt并从测试目录运行py.test -s,您应该会看到两个打印语句。

我在这里的绳子尽头 - 我必须有一些我想念的东西,但对于我的生活,我似乎无法找到它。

帮助我,所以,你是我唯一的希望!

3 个答案:

答案 0 :(得分:2)

您可能想尝试pytest-flask-sqlalchemy-transactions。它是一个插件,它公开了一个db_session固定装置,可以实现您所需要的功能:允许您运行数据库更新,这些更新将在测试退出时回滚。该插件基于Alex Michael的博客文章,并为嵌套事务提供了一些其他支持,涵盖了更多的用户案例。还有一些配置选项可用于在应用程序中模拟可连接对象,因此您也可以从代码库中运行任意方法。

对于test_accounts.py,您可以执行以下操作:

from example import db, Account


class TestAccounts(object):

    def test_update_view(self, db_session):

        test_acct = Account(username='abc')

        db_session.add(test_acct)
        db_session.commit()

        resp = self.client.post('/update',
                                data={'a':1},
                                content_type='application/json')

        assert resp.status_code == 200

该插件需要通过_db固定装置访问数据库,但是由于您已经在db中定义了conftest.py固定装置,因此可以轻松设置数据库访问权限:

@pytest.fixture(scope='session')
def _db(db):
    return db

您可以在the docs中找到有关如何设置和安装的详细信息。希望这会有所帮助!

答案 1 :(得分:0)

我也遇到了回滚问题,我的代码可以找到here

阅读完一些文档后,似乎应该在会话中调用begin()函数。

因此,在您的情况下,我会将会话夹具更新为:

@pytest.yield_fixture(scope='function', autouse=True)
def session(db, request):
    """Creates a new database session for a test."""

    db.session.begin()

    yield db.session

    db.session.rollback()
    db.session.remove()

我没有测试过这段代码,但是当我在代码上尝试时,我收到以下错误:

INTERNALERROR> Traceback (most recent call last):
INTERNALERROR>   File "./venv/lib/python2.7/site-packages/_pytest/main.py", line 90, in wrap_session
INTERNALERROR>     session.exitstatus = doit(config, session) or 0
...
INTERNALERROR>   File "./venv/lib/python2.7/site-packages/_pytest/python.py", line 59, in filter_traceback
INTERNALERROR>     return entry.path != cutdir1 and not entry.path.relto(cutdir2)
INTERNALERROR> AttributeError: 'str' object has no attribute 'relto'

答案 2 :(得分:0)

from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from unittest import TestCase

# global application scope.  create Session class, engine
Session = sessionmaker()

engine = create_engine('postgresql://...')

class SomeTest(TestCase):
    def setUp(self):
        # connect to the database
        self.connection = engine.connect()

        # begin a non-ORM transaction
        self.trans = self.connection.begin()

        # bind an individual Session to the connection
        self.session = Session(bind=self.connection)

    def test_something(self):
        # use the session in tests.

        self.session.add(Foo())
        self.session.commit()

    def tearDown(self):
        self.session.close()

        # rollback - everything that happened with the
        # Session above (including calls to commit())
        # is rolled back.
        self.trans.rollback()

        # return connection to the Engine
        self.connection.close()

sqlalchemy doc has solution for the case