Python 在SqlAlchemy集成测试之间是否有更简单的方法来恢复状态?

Python 在SqlAlchemy集成测试之间是否有更简单的方法来恢复状态?,python,flask,sqlalchemy,integration-testing,flask-sqlalchemy,Python,Flask,Sqlalchemy,Integration Testing,Flask Sqlalchemy,烧瓶示例应用程序,并在每次测试之间创建、删除和重新设定其整个数据库的种子。即使这不会使测试套件运行缓慢,我想知道是否有一种方法可以在不那么“破坏性”的情况下完成同样的事情。我很惊讶没有一种“更软”的方法来回滚任何更改。我试过一些没用的东西 对于上下文,我的测试使用self.client.post('/things')之类的东西通过Flask test_客户端调用端点,并在端点会话中调用.commit() 我曾尝试创建自己的“提交”函数,实际上只在测试期间刷新,但如果我发出两个连续请求,如self

烧瓶示例应用程序,并在每次测试之间创建、删除和重新设定其整个数据库的种子。即使这不会使测试套件运行缓慢,我想知道是否有一种方法可以在不那么“破坏性”的情况下完成同样的事情。我很惊讶没有一种“更软”的方法来回滚任何更改。我试过一些没用的东西

对于上下文,我的测试使用self.client.post('/things')之类的东西通过Flask test_客户端调用端点,并在端点会话中调用.commit()

我曾尝试创建自己的“提交”函数,实际上只在测试期间刷新,但如果我发出两个连续请求,如self.client.post('/things')和self.client.get('/things'),则新创建的项不会出现在结果集中,因为新请求具有新的请求上下文和新的DB会话(和事务)它不知道仅仅是刷新而不是提交的更改。这似乎是这种方法不可避免的问题

我曾尝试在db.session.begin(subtransactions=True)中使用子事务,但后来遇到了更糟糕的问题。因为我的autoflush=False,所以在提交外部事务之前,实际上不会提交或刷新任何内容。因此,任何依赖于同一测试中先前请求修改的数据的请求都将失败。即使使用autoflush=True,顺序请求也会出现前面的问题

我尝试过嵌套事务,其结果与子事务相同,但显然它们没有达到我所希望的效果。我看到嵌套事务向数据库发出保存点命令。我希望这将允许提交发生,对其他会话可见,然后能够在任意时间回滚到该保存点,但这不是他们所做的。它们在事务中使用,与前面的方法有相同的问题

更新:在连接上而不是会话上使用嵌套事务,这可能会起作用,但需要对应用程序进行一些重新构造,以使用由测试代码创建的连接。我还没试过这个。我最终会找到解决办法的,但同时我希望还有别的办法。有人说这种方法是由于“”和保存点之间的区别,但也有人说使用保存点而不是尝试嵌套事务。我认为我们可以无视这一警告。我再也看不到这两个数据库之间有什么区别了,如果它在一个数据库上工作,那么在另一个数据库上也可能工作

另一个避免DB drop_all、create_all和使用数据重新设定种子的选项是手动取消执行测试引入的更改。但是在测试端点时,可以将许多行插入到许多表中,并且手动可靠地撤消这一操作会使人筋疲力尽,并且容易出现错误

在尝试了所有这些之后,我开始看到在测试之间放弃和创造的智慧。然而,是否有我在上面尝试过的东西应该有效,但我只是做了一些不正确的事情?还是有人知道我还没有尝试过的另一种方法


更新:是截断所有表,而不是删除和创建它们。这显然是速度的两倍,但它似乎仍然很繁重,没有回滚方便(回滚不会删除测试用例之前放入数据库中的任何样本数据)。

对于单元测试,我认为重新生成整个数据库的标准方法是最有意义的,正如你在我和其他许多例子中看到的那样。但我同意,对于大型应用程序,在测试运行期间,这可能需要很多时间

多亏了SQLAlchemy,您可以编写大量运行在生产数据库(可能是MySQL、Postgres等)上的通用数据库代码,同时在sqlite上运行测试。不可能每个应用程序都使用100%的通用SQLAlchemy,因为sqlite和其他应用程序有一些重要的区别,但在许多情况下,这很有效

所以只要有可能,我就为我的测试建立一个sqlite数据库。即使对于大型数据库,使用内存中的sqlite数据库也应该非常快。另一个非常快速的替代方法是生成一次表,用所有emtpy表备份sqlite文件,然后在每次测试之前恢复文件,而不是执行
create\u all()

我还没有探讨过使用空表对数据库进行初始备份,然后在MySQL或Postgres测试之间使用基于文件的恢复的想法,但从理论上讲,这应该也可以,所以我想这是您在列表中没有提到的一种解决方案。不过,您需要在测试之间停止并重新启动db服务