You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免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,提问作者정준호

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 10:46:10