gpt4 book ai didi

java - 使用 JUnit 和 Spring 测试应用程序的持久性重启

转载 作者:行者123 更新时间:2023-11-30 10:15:49 24 4
gpt4 key购买 nike

我有一个使用持久 JMS 队列的应用程序。想象一下,我在阅读消息之后和确认消息之前遇到应用程序故障。持久队列必须在应用程序重新启动后再次提供该消息。我如何为此实现 junit 集成测试?我正在测试应用程序在(模拟的)应用程序在“事务”中崩溃后重新启动。

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

前世我手动写了关闭spring context的代码,然后手动重启了一个新的context。例如。在 A) 和 B) 之间。这可以在单个测试用例中完成。它不会很好地与 @RunWith(SpringRunner.class) 一起玩,我猜,而且看起来很老派。考虑到如今所有出色的 Spring 和 JUnit 支持,这真的是唯一的选择吗?

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

最佳答案

以下文章How to Restart a Spring Application Context within a JUnit test描述问题的解决方案。


解决方案包括扩展 SpringJUnit4ClassRunner 以注入(inject)一个 SpringRestarter 单例,它负责重述应用程序上下文。

public class SpringRestarter {

private static SpringRestarter INSTANCE = null;

private TestContextManager testContextManager;

public static SpringRestarter getInstance() {
if (INSTANCE == null) {
INSTANCE = new SpringRestarter();
}

return INSTANCE;
}

public void init(TestContextManager testContextManager) {
this.testContextManager = testContextManager;
}

public void restart(Runnable stoppedLogic) {
testContextManager.getTestContext().markApplicationContextDirty(DirtiesContext.HierarchyMode.EXHAUSTIVE);

if (stoppedLogic != null) {
stoppedLogic.run();
}

testContextManager.getTestContext().getApplicationContext();
reinjectDependencies();
}

private void reinjectDependencies() {
testContextManager
.getTestExecutionListeners()
.stream()
.filter(listener -> listener instanceof DependencyInjectionTestExecutionListener)
.findFirst()
.ifPresent(listener -> {
try {
listener.prepareTestInstance(testContextManager.getTestContext());
} catch (Exception e) {
e.printStackTrace();
}
});
}
}

RestartingSpringJUnit4ClassRunner 扩展 SpringJUnit4ClassRunner 并初始化单例 SpringRestarter

public class RestartingSpringJUnit4ClassRunner extends SpringJUnit4ClassRunner {

public RestartingSpringJUnit4ClassRunner(Class<?> clazz) throws InitializationError {
super(clazz);
}

@Override
protected TestContextManager createTestContextManager(Class<?> clazz) {

final TestContextManager testContextManager = super.createTestContextManager(clazz);

SpringRestarter.getInstance().init(testContextManager);
return testContextManager;
}
}

RestartingSpringRunner extends RestartingSpringJUnit4ClassRunner 为了扩展 SpringRunner

public class RestartingSpringRunner extends RestartingSpringJUnit4ClassRunner {

public RestartingSpringRunner(Class<?> clazz) throws InitializationError {
super(clazz);
}
}

在 JUnit 4 测试中使用

@RunWith(RestartingSpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MyIntegrationTests {

public void myRestartingTest() {
//Some test logic before the context restart

SpringRestarter.getInstance().restart(() -> {/* Some logic after context stopped */});

//Some test logic after the context restart
}
}

Full details of the explanation

关于java - 使用 JUnit 和 Spring 测试应用程序的持久性重启,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50302036/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com