Flask-SQLAlchemy集成测试无法找到回滚更改的方法

时间:2013-11-11 05:20:18

标签: python unit-testing sqlalchemy flask flask-sqlalchemy

我正在尝试学习烧瓶技术堆栈,而对于我的应用程序,我正在使用Flask-SQLAlchemy。一切都很完美,但我正在努力编写集成测试。我不想使用SQLite,因为在生产中我使用PostgreSQL并且放置大量的模拟实际上会更多地测试我自己的实现而不是逻辑本身。

因此,经过一些研究后,我决定实施将测试数据写入测试数据库的测试,并在每次测试后回滚更改(为了性能)。实际上,我正在尝试实现类似于这种方法的东西:http://sontek.net/blog/detail/writing-tests-for-pyramid-and-sqlalchemy

我的问题是创建正确的事务并能够回滚它。这是我的基类的代码:

from flask.ext.sqlalchemy import SQLAlchemy
db = SQLAlchemy()

class MyAppIntegrationTestCase(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
    app.config['TESTING'] = True
    app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql+psycopg2:///db_test'
    init_app()
    db.app = app
    db.create_all(app=app)

    @classmethod
    def tearDownClass(cls):
        db.drop_all(app=app)

    def setUp(self):
        db.session.rollback()
        self.trans = db.session.begin(subtransactions=True)

    def tearDown(self):
        self.trans.rollback()

当我尝试执行测试时,出现以下错误:

Traceback (most recent call last):
 File "myapp/src/core/tests/__init__.py", line 53, in tearDown
   self.trans.rollback()
 File "myapp/venv/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 370, in rollback
   self._assert_active(prepared_ok=True, rollback_ok=True)
 File "myapp/venv/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 203, in _assert_active
   raise sa_exc.ResourceClosedError(closed_msg)
ResourceClosedError: This transaction is closed

我敢打赌,这是scoped_session的问题,当我运行测试时,它会为所有测试重用一个全局会话,但我在SQLAlchemy中的知识还不够深入。

任何帮助将受到高度赞赏! 谢谢!

3 个答案:

答案 0 :(得分:0)

你的tearDownClass和setUpClass导致了这些问题。

在所有测试之前调用setUpClass,并且tearDownClass在类中的所有测试之后。

所以如果你有3个测试。

setUpClass被称为

setUp被称为

tearDown被调用(你回滚,但是你没有开始会话,这会引发错误)

调用setUp(另一个回滚的错误)

等...

将db.session.begin添加到你的tearDown中,你会没事的。

from flask.ext.sqlalchemy import SQLAlchemy
db = SQLAlchemy()

class MyAppIntegrationTestCase(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        app.config['TESTING'] = True
        app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql+psycopg2:///db_test'
        init_app()
        db.app = app
        db.create_all(app=app)

    @classmethod
    def tearDownClass(cls):
        db.drop_all(app=app)

    def setUp(self):
        db.session.rollback()
        self.trans = db.session.begin(subtransactions=True)

    def tearDown(self):
        self.trans.rollback()
        db.session.begin()

答案 1 :(得分:0)

我写了一篇关于如何设置它的博客文章...简而言之,你必须创建一个嵌套事务,以便你的应用程序内的任何session.commit()调用都不会破坏你的隔离。然后将侦听器应用于内部事务,以便在有人尝试提交或回滚时重新启动它。 Setup Flask-Sqlalchemy Transaction Test Case

答案 2 :(得分:0)

您问题的可能解决方案:

如果您的数据库的数据大小不是很大并且您希望保持数据不变,您可以在设置中进行备份(通过直接写sql句子)

"CREATE TABLE {0}_backup SELECT * FROM {0}".format(table_name)

并在拆解中恢复

"DROP TABLE {0}".format(table_name)
"RENAME TABLE {0}_backup TO {0}".format(table_name)