在测试套件中使用外部事务

时间:2016-11-13 18:24:19

标签: flask-sqlalchemy python-unittest

External transactions

我想将一个或多个模型提交到数据库,并在每次测试后回滚它们。纯sqlalchemy实现(在底部)以我期望的方式工作。但是,flask-sqlalchemy实现无法在每次测试后回滚已提交的模型。

如何将flask-sqlalchemy的作用域会话绑定到引擎的连接?

通用flask app:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy


app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://'
db = SQLAlchemy(app)


class A(db.Model):
    id = db.Column(db.Integer, primary_key=True)

flask-sqlalchemy testcase(不回滚):

from app import *
from unittest import TestCase


class Test(TestCase):

    def setUp(self):
        self.connection = db.engine.connect()
        self.transaction = self.connection.begin()

        options = dict(bind=self.connection, binds={})
        self.session = db.create_scoped_session(options=options)
        db.session = self.session

        self.addCleanup(self.cleanup)

    def cleanup(self):
        self.transaction.rollback()
        self.connection.close()
        self.session.remove()

    @classmethod
    def setUpClass(cls):
        db.create_all()

    @classmethod
    def tearDownClass(cls):
        pass

    def test_1(self):
        a = A()
        db.session.add(a)
        db.session.commit()

        assert len(db.session.query(A).all()) == 1

    def test_2(self):
        assert len(db.session.query(A).all()) == 0  # len is 1

sqlalchemy testcase(有效):

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
from unittest import TestCase


Base = declarative_base()


class A(Base):
    __tablename__ = 'test'
    id = Column(Integer, primary_key=True)


class Test(TestCase):

    def setUp(self):
        self.connection = e.connect()
        self.transaction = self.connection.begin()

        # Begin scoped session
        factory = sessionmaker(bind=self.connection)
        self.session = scoped_session(factory)

        self.addCleanup(self.cleanup)

    def cleanup(self):
        self.session.close()
        self.transaction.rollback()
        self.connection.close()

    @classmethod
    def setUpClass(cls):
        global e

        e = create_engine("sqlite://")
        Base.metadata.create_all(e)

    @classmethod
    def tearDownClass(cls):
        pass

    def test_1(self):
        a = A()
        self.session.add(a)
        self.session.commit()

        assert len(self.session.query(A).all()) == 1

    def test_2(self):
        assert len(self.session.query(A).all()) == 0

1 个答案:

答案 0 :(得分:1)

我遇到了同样的问题,也许我的修复与你的一样。

这是我的setUp和tearDown:

import unittest
from my_app import db

class Test(unittest.TestCase):
    def setUp(self):
        self.connection = db.engine.connect()
        self.trans = self.connection.begin()
        db.session.configure(bind=self.connection, binds={})

    def tearDown(self):
        self.trans.rollback()
        self.connection.close()
        db.session.remove()

对我来说实际上是在添加:

binds={}

我还没有真正调查过为什么会修复它,但它确实适用于我。如果有人知道为什么空的dict绑定可以修复问题,我很乐意听到。