事务管理器撤销/回滚最后一次提交

15 投票
2 回答
13519 浏览
提问于 2025-04-18 15:18

我想通过把测试数据放到测试用例的 setUp() 方法中,改成放到 setUpClass()/teardownClass 这个类方法里,来加快我的测试速度。这样就不用为每个测试都重新创建相同的测试数据了。

@classmethod
def setUpClass(cls):
    plant.StuffFactory() #plant stuff with FactoryBoy
    transaction.commit()

@classmethod
def tearDownClass(cls):
    session.query(models.Stuff).delete() # delete planted stuff
    transaction.commit()

但是我不喜欢自己用 session.delete 来删除东西,因为我用的模型很多,不想去追踪我放了什么。我想要一种像这样的方式:

@classmethod
def tearDownClass(cls):
    session.clear() #delete all
    transaction.commit()

不过 session.close()session.remove() 并不会影响已经提交的数据。所以我在寻找一种方法,像是“取消” setUpClasstransaction.commit(),就好像我什么都没放过一样。

我尝试了嵌套事务和保存点,但这些方法只有在数据还没提交的时候才有效。

有没有什么建议?

2 个回答

1

setUpClass() 这个方法里,你可以创建一个保存点,像这样:

sp = transaction.savepoint()

然后在 tearDownClass() 这个方法里,你只需要使用:

sp.rollback()

希望这对你有帮助。

11

如果你不想让某些操作被提交,就不要调用 transaction.commit() 这个方法哦 :)

@classmethod
def setUpClass(cls):
    plant.StuffFactory() #plant stuff with FactoryBoy
    # you may possibly want to flush the session, so everything has proper IDs etc.
    DBSession.flush() 
    # let the transaction continue for the duration of the test

@classmethod
def tearDownClass(cls):
    # let the database make everything as if nothing happened
    transaction.rollback()

这样做的前提是,你的测试代码里不能直接管理事务(比如在应用代码中使用 transaction.commit()transaction.rollback()),不过这样做本来就是个坏习惯:

一般来说,应用程序应该在处理特定数据的函数外部管理会话的生命周期。这是一个基本的关注点分离原则,可以让数据操作与访问和处理这些数据的上下文无关。

会话基础知识,SQLAlchemy 文档(https://docs.sqlalchemy.org/en/13/orm/session_basics.html

撰写回答