我有一个带Spring Data Rest的Spring Boot应用程序,我在集成测试中使用@WebIntegrationTest
和TestRestTemplate
。测试的基类看起来像这样:
@RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles(profiles = "test")
@SpringApplicationConfiguration(classes = Application.class)
@Transactional
@TransactionConfiguration
@WebIntegrationTest("server.port: 0")
public abstract class IntegrationTest {
...
}
我正在使用TestRestTemplate
对资源执行POST
请求来测试实体的创建。问题是,即使我的测试被配置为事务性的,也不会回滚在数据库上持久保存实体的事务,因此实验在测试后仍保留在数据库中。我有点明白,因为在测试中回滚的事务与持久化实体的事务不同。
现在我的问题是,有没有办法在测试方法中回滚通过RestTemplate
发出的请求触发的交易?
答案 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,而不是使用TestRestTemplate
或RestTemplate
。在这种情况下,@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分钟(同时使测试保持绿色;)),这是一个不错的选择。
希望这对某人有帮助。