如何避免Spring ContextClosedEvent在Java测试时触发消息发送?
解决Spring ContextClosedEvent在测试中触发消息发送的问题
可以通过以下几种方案避免测试时触发关闭消息发送:
方案1:通过环境Profile区分执行逻辑
利用Spring的Profile机制,判断当前是否处于测试环境,仅在非测试环境下执行消息发送逻辑。
修改原监听类,注入Environment并判断活跃Profile:
package com.nhnacademy.aiot.ruleengine.listener; import com.nhnacademy.aiot.ruleengine.send.MessageSender; import lombok.RequiredArgsConstructor; import org.jetbrains.annotations.NotNull; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextClosedEvent; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; import java.util.Arrays; @Component @RequiredArgsConstructor public class ServerClosedMessageSender implements ApplicationListener<ContextClosedEvent> { private final MessageSender messageSender; private final Environment environment; @Override public void onApplicationEvent(@NotNull ContextClosedEvent event) { // 检查是否存在测试环境Profile boolean isTestEnvironment = Arrays.stream(environment.getActiveProfiles()) .anyMatch(profile -> profile.equalsIgnoreCase("test")); if (!isTestEnvironment) { messageSender.send("RuleEngine", "Rule Engine server shutdown!!"); } } }
测试时激活test Profile(比如在测试类上添加@ActiveProfiles("test")),即可跳过消息发送逻辑。
方案2:测试环境替换监听Bean
通过测试专用配置,替换生产环境的监听Bean为不执行任何操作的实现,实现测试与生产逻辑的隔离。
方式A:给原Bean添加Profile限制
修改原监听类,指定仅在非测试环境生效:
@Component @RequiredArgsConstructor @Profile("!test") // 仅当test Profile未激活时生效 public class ServerClosedMessageSender implements ApplicationListener<ContextClosedEvent> { private final MessageSender messageSender; @Override public void onApplicationEvent(@NotNull ContextClosedEvent event) { messageSender.send("RuleEngine", "Rule Engine server shutdown!!"); } }
然后创建测试环境的空实现Bean:
@Configuration @Profile("test") public class TestShutdownListenerConfig { @Bean public ApplicationListener<ContextClosedEvent> testServerClosedMessageSender() { // 空实现,不发送消息 return event -> {}; } }
方式B:测试类中Mock MessageSender
在测试类中使用@MockBean替换原MessageSender,让send方法无实际执行逻辑:
@SpringBootTest @ActiveProfiles("test") public class YourTestClass { // Mock MessageSender,send方法默认不执行任何操作 @MockBean private MessageSender messageSender; // 测试逻辑代码... }
方案3:通过上下文类型判断(不推荐)
通过判断ApplicationContext的类型是否为测试相关类,来决定是否发送消息。这种方法依赖Spring测试上下文的类名,可能因版本或测试框架变化失效,仅作为补充方案:
@Override public void onApplicationEvent(@NotNull ContextClosedEvent event) { ApplicationContext context = event.getApplicationContext(); // 判断上下文类名是否包含测试标识 boolean isTestContext = context.getClass().getName().contains("Test"); if (!isTestContext) { messageSender.send("RuleEngine", "Rule Engine server shutdown!!"); } }
推荐优先使用方案1或方案2,这两种方法逻辑清晰、稳定性高,能有效隔离测试与生产环境的行为。
内容的提问来源于stack exchange,提问作者정준호
相关产品推荐
相关产品推荐

