Grails:集成测试中的事务

Grails:集成测试中的事务,grails,integration-testing,Grails,Integration Testing,我有一个非常简单的设置——一个调用服务方法的控制器。在这个服务中,我将一个对象保存到DB中,并使用注入的JMSTemplate将JMS消息发送到队列(保存后)。默认情况下,该服务已启用事务 在ActiveMQ服务器关闭的情况下手动测试时,会抛出异常并回滚事务,其净效果是对象也不会保存到数据库中。一切都好 但是,当我通过集成测试(ActiveMQ仍处于关闭状态)运行此测试时,我用来检查对象在调用控制器后是否未使用计数查询保存在DB中的断言失败,并表示计数为1。我已经通过在测试开始时添加另一个断言来

我有一个非常简单的设置——一个调用服务方法的控制器。在这个服务中,我将一个对象保存到DB中,并使用注入的JMSTemplate将JMS消息发送到队列(保存后)。默认情况下,该服务已启用事务

在ActiveMQ服务器关闭的情况下手动测试时,会抛出异常并回滚事务,其净效果是对象也不会保存到数据库中。一切都好

但是,当我通过集成测试(ActiveMQ仍处于关闭状态)运行此测试时,我用来检查对象在调用控制器后是否未使用计数查询保存在DB中的断言失败,并表示计数为1。我已经通过在测试开始时添加另一个断言来确认DB在测试开始时没有任何这些对象,以确保计数为0

这是预期的行为(可能是由于集成测试环境中事务的性质)还是我可能做错了什么?由于JMS服务器已关闭,并且是RuntimeException,因此仍会引发异常


给人的印象是这是意料之中的-在这种情况下,关于如何在集成测试中测试事务行为的最佳实践,是否有任何建议?

不确定为什么每个人都发表了评论而不是回答,因为评论确实暴露了答案。我要跳进去试着找出答案

是的,在Spock测试中,整个测试,包括When、thens、givens等,都在同一事务中运行。因此,在测试完成之前,您不会看到希望的回滚

您可以通过在测试类的顶部添加“statictransactional=false”将测试设置为非事务性。当然,结果是,在测试运行之后,您需要清理数据库(如果数据库卫生对您很重要的话)。这里的一个大问题是Grails IntegrationSpec类中有一个bug,每当您尝试将transactional设置为false时,该bug就会爆发。这样就有了解决该问题的方法:


基本上,将grails.test.spock.IntegrationSpec的所有代码复制到您自己的类中,并将一些方法替换为尊重测试事务性质的版本。

如果我没记错的话,直到测试完成后事务才会回滚。因此,当您执行断言时,数据似乎保存到了数据库中,因为该事务尚未回滚。是的,似乎确实如此,因为相同的事务似乎在测试和控制器之间使用。我想知道在这样的情况下是否有一个标准的范例可以使用。我不想仅仅为了测试而更改控制器代码,以使其需要一个新的事务。这篇博文展示了如何使测试成为非事务性的,这将导致控制器和服务拥有自己的事务(而不是使用测试的事务)。缺点是,如果没有抛出异常,事务将提交,您必须自己清理。