我一直在测试@TransactionalEvents
(Spring 4.2 https://spring.io/blog/2015/02/11/better-application-events-in-spring-framework-4-2的一个特性)与我们现有的Spring JUnit测试(通过@TransactionalTestExecutionListener
或子类AbstractTransactionalUnit4SpringContextTests
运行,但是,似乎有一个被迫的选择-要么在没有@Rollback
注解的情况下运行测试,有没有人遇到过一个好方法来测试@TransactionalEvents,同时能够@Rollback测试?
4条答案
按热度按时间lfapxunr1#
Stéphane Nicoll是正确的:如果
@TransactionalEventListener
的TransactionPhase
被设置为AFTER_COMMIT
,那么使用自动回滚语义进行事务测试就没有任何意义,因为事件永远不会被触发。换句话说,如果事务从未提交,则无法在事务提交后触发事件。
因此,如果你真的希望事件被触发,你必须让事务被提交(例如,通过使用
@Commit
注解你的测试方法)。要在提交后进行清理,你应该能够在事务提交后 * 以 isolated 模式使用@Sql
执行清理脚本。例如,像下面这样的东西(未经测试的代码)可能对你有用:字符串
此致,
Sam(* Spring TestContext Framework的作者 *)
vx6bjr1n2#
Marco的解决方案是可行的,但是将REQUIRES_NEW传播添加到业务代码中并不总是可以接受的。
所以我们应该假设我们只能改变测试部分。
电磁阀1
字符串
该方案将真实的服务封装到测试组件中,测试组件可以使用REQUIRES_NEW传播进行修饰,除了测试之外,该方案不修改其他逻辑。
方案二
型
这是最简单的解决方案。我们可以结束测试事务并将其标记为提交。这将强制处理事务性事件。如果测试更改数据,则必须指定清理SQL脚本,否则我们会引入提交修改数据的副作用。
eivgtgni3#
萨姆·布兰南的解决方案几乎适用于亚当的评论。
实际上,用
@TransactionalEventListener
标注的方法是在测试方法事务提交之后被调用的。这是因为引发事件的调用方法是在逻辑事务中执行的,而不是物理事务。相反,当调用方法在一个新的物理事务中执行时,用
@TransactionalEventListener
注解的方法会在正确的时间被调用,即在测试方法事务被提交之前。另外,我们在测试方法上不需要
@Commit
,因为我们实际上并不关心这些事务。然而,我们确实需要Sam Brannen解释的@Sql(...)
语句来撤销调用方法的已提交更改。看下面的小例子。
首先是提交事务时调用的侦听器(
@TransactionalEventListener
的默认行为):字符串
然后是发布上述类监听的事件的application service。请注意,每次调用方法时transactions都被配置为新的物理transactions(有关更多详细信息,请参阅Spring Framework文档):
型
最后,Sam Brannen提出的测试方法,但没有
@Commit
注解,此时不需要:型
这样做就像一个魅力:-)
l3zydbqr4#
只是为了历史记录。我通过模板创建新的交易
字符串