Spring Boot @WebIntegrationTest和TestRestTemplate - 是否可以回滚测试事务?

时间:2015-04-17 11:47:25

标签: spring spring-boot spring-data-rest spring-test

我有一个带Spring Data Rest的Spring Boot应用程序,我在集成测试中使用@WebIntegrationTestTestRestTemplate。测试的基类看起来像这样:

@RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles(profiles = "test")
@SpringApplicationConfiguration(classes = Application.class)
@Transactional
@TransactionConfiguration
@WebIntegrationTest("server.port: 0")
public abstract class IntegrationTest {

   ...

}

我正在使用TestRestTemplate对资源执行POST请求来测试实体的创建。问题是,即使我的测试被配置为事务性的,也不会回滚在数据库上持久保存实体的事务,因此实验在测试后仍保留在数据库中。我有点明白,因为在测试中回滚的事务与持久化实体的事务不同。

现在我的问题是,有没有办法在测试方法中回滚通过RestTemplate发出的请求触发的交易?

3 个答案:

答案 0 :(得分:22)

  

有没有办法回滚由该触发的交易   在测试方法中通过RestTemplate提出的请求?

没有。无法回滚已部署的应用程序管理的事务。

当您使用@WebIntegrationTest@SpringApplicationConfiguration注释测试类时,Spring Boot将启动一个嵌入式Servlet容器并在其中部署您的应用程序。因此,从这个意义上说,您的测试和应用程序在两个不同的过程中运行。

Spring TestContext Framework 仅管理Test-managed transactions。因此,测试类中@Transactional的存在仅影响本地测试管理的事务,而不影响不同进程中的事务。

正如其他人已经提到的,解决方法是在测试完成后重置数据库的状态。为此你有几个选择。有关详细信息,请参阅参考手册的Executing SQL scripts部分。

此致

Sam( Spring TestContext Framework的作者

答案 1 :(得分:0)

您可以使用MockMvc,而不是使用TestRestTemplateRestTemplate。在这种情况下,@Transactional将回滚数据更改。

如果您正在@RestController中测试POST操作中的逻辑,那么MockMvc就足够了。如果您的测试涉及过滤器,那么您可能需要使用TestRestTemplate。在这种情况下,正如其他人指出的那样,您需要在测试结束时重置数据库中的测试数据。

答案 2 :(得分:0)

我最近需要这个,因为我们的1300+集成测试花费了+ -70分钟,并且可行,但是需要一些底层的管道。

由于测试用例和启动服务器的内存是共享的,因此我通过编写DataSource实现来使它工作,该实现仅管理1个连接,并将该连接返回给getConnection()的任何调用方。连接本身是一个Connection实现,它充当实际连接的包装。
然后将数据源添加到@SpringBootTest配置中。

我不会在此处(公司属性)发布代码,但以下是主要详细信息:

DataSource将Connection包装器维护为静态字段。
在dataSource.getConnection()上,所有“借款人”的计数器都会增加。
在connection.close()之后,此计数器递减。如果变为0,则表示测试用例已结束,事务可以回滚。

要考虑1个陷阱,这就是春季的事务管理:您必须模拟事务回滚。
为此,我在每个connection.open()上创建一个保存点(connection.setSavePoint()),并将其推送到LinkedList中。对于任何connection.rollback(),我都将其从堆栈中弹出并执行connection.rollback(savePoint)。

我还不得不破解启用提交功能的可能性,因为必须在@BeforeAll()中创建数据库。
在我的测试案例中,我不依赖@Transactional,而是在抽象父级的@Before / @After方法中调用dataSource.getConnection / connection.close()来标记事务边界。

这不是最漂亮的解决方案,但这将测试时间从70分钟减少到了30分钟(同时使测试保持绿色;)),这是一个不错的选择。

希望这对某人有帮助。