Java 使用JUnit和Spring使用持久性测试应用程序重启

Java 使用JUnit和Spring使用持久性测试应用程序重启,java,spring,junit,jms,persistence,Java,Spring,Junit,Jms,Persistence,我有一个使用持久JMS队列的应用程序。想象一下,我在阅读一条消息之后,在确认它之前,应用程序失败了。永久队列必须在应用程序重新启动后再次提供该消息。我如何为此实现junit集成测试?我正在测试一个(模拟的)应用程序崩溃后的应用程序重启 我已经将@DirtiesContext作为重置应用程序所有Spring部分的一种方法:读取配置,重新创建JMS连接。我可以让一个测试用例A)编写一条消息,允许读取该消息,然后在不确认的情况下“退出”(关闭spring上下文?)。然后另一个测试用例(在重新加载上下文

我有一个使用持久JMS队列的应用程序。想象一下,我在阅读一条消息之后,在确认它之前,应用程序失败了。永久队列必须在应用程序重新启动后再次提供该消息。我如何为此实现junit集成测试?我正在测试一个(模拟的)应用程序崩溃后的应用程序重启

我已经将
@DirtiesContext
作为重置应用程序所有Spring部分的一种方法:读取配置,重新创建JMS连接。我可以让一个测试用例A)编写一条消息,允许读取该消息,然后在不确认的情况下“退出”(关闭spring上下文?)。然后另一个测试用例(在重新加载上下文B之后)读取消息并断言在模拟应用程序重新启动后消息没有丢失。但是,
@DirtiesContext
提供的内置上下文重载只在测试用例之间发生。JUnit并没有提供一种方法来对两个测试用例进行排序,或者使B)依赖于a),这样,如果您决定运行B),a)将始终运行(并且首先运行)

在以前的生活中,我编写了手动代码来关闭spring上下文,然后手动重新启动一个新上下文。例如,在A)和B)之间。这可以在单个测试用例中完成。我猜,它与
@RunWith(SpringRunner.class)
不太合拍,而且看起来很老派。考虑到这些天对Spring和JUnit的支持,这真的是唯一的选择吗

这似乎是一种非常有用的技术。它可以用来测试消息被回滚(并卡在死信队列中)后的重新到达;或者,写入数据库的序列号在“崩溃”期间确实持续存在。由于持久化(或非持久化)数据而影响下一次应用程序启动的任意数量的故障案例。我们如何在junit测试中模拟spring重启?在一个测试中,或者创建一系列相互依赖的测试,测试之间使用
@DirtiesContext

下面的文章介绍了该问题的解决方案


解决方案包括扩展
SpringJUnit4ClassRunner
,以注入负责重新启动应用程序上下文的
SpringRestarter
singleton

公共类SpringRestarter{
私有静态SpringRestarter实例=null;
私有TestContextManager TestContextManager;
公共静态SpringRestarter getInstance(){
if(实例==null){
实例=新的SpringRestarter();
}
返回实例;
}
公共void init(TestContextManager TestContextManager){
this.testContextManager=testContextManager;
}
公共无效重新启动(可运行的stoppedLogic){
testContextManager.getTestContext().markApplicationContextDirty(DirtiesContext.HierarchyMode.definancial);
如果(stoppedLogic!=null){
stoppedLogic.run();
}
testContextManager.getTestContext().getApplicationContext();
reinjectDependencies();
}
私有void reinjectDependencies(){
testContextManager
.getTestExecutionListeners()
.stream()
.filter(侦听器->DependencyInjectionTestExecutionListener的侦听器实例)
.findFirst()
.ifPresent(侦听器->{
试一试{
prepareTestInstance(testContextManager.getTestContext());
}捕获(例外e){
e、 printStackTrace();
}
});
}
}
RestartingSpringJUnit4ClassRunner
扩展
SpringJUnit4ClassRunner
并初始化singleton
SpringRestarter

公共类重新启动SpringJUnit4ClassRunner扩展SpringJUnit4ClassRunner{
公共重新启动SpringJUnit4ClassRunner(类clazz)引发初始化错误{
超级(clazz);
}
@凌驾
受保护的TestContextManager createTestContextManager(clazz类){
最终TestContextManager TestContextManager=super.createTestContextManager(clazz);
SpringRestarter.getInstance().init(testContextManager);
返回testContextManager;
}
}
RestartingSpringRunner
扩展
RestartingSpringJUnit4ClassRunner
以扩展
SpringRunner

public类RestartingSpringRunner扩展RestartingSpringJUnit4ClassRunner{
公共重新启动SpringRunner(类clazz)引发初始化错误{
超级(clazz);
}
}
在JUnit4测试中使用

@RunWith(重新启动SpringRunner.class)
@SpringBootTest(webEnvironment=SpringBootTest.webEnvironment.RANDOM\u端口)
公共类MyIntegrationTests{
public void myRestartingTest(){
//上下文重新启动前的一些测试逻辑
SpringRestarter.getInstance().restart(()->{/*上下文停止后的一些逻辑*/});
//上下文重新启动后的一些测试逻辑
}
}