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

Spring Boot Cucumber测试因被调用模块System.exit终止如何解决

你配置的System Rules不生效是因为Cucumber测试的执行生命周期由Cucumber独立的运行器管理,并不识别JUnit的@Rule注解,因此定义在步骤类中的拦截规则根本不会被加载触发。

可行解决方案

方案1:使用System Lambda库(适配Cucumber,推荐)

System Lambda是System Rules的无Rule衍生版本,不需要依赖JUnit的生命周期注解,可直接嵌入任意测试代码中拦截System.exit调用。
首先引入Maven依赖:

<dependency>
    <groupId>com.github.stefanbirkner</groupId>
    <artifactId>system-lambda</artifactId>
    <version>1.2.1</version>
    <scope>test</scope>
</dependency>

修改步骤定义代码如下:

import static com.github.stefanbirkner.systemlambda.SystemLambda.catchSystemExit;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class StepDefs{
    @When("^the function is executed$")
    public void functionIsExecuted() throws Exception {
        System.out.println("This is executed right before System.exit().");
        String[] args = {"some args"};
        // 拦截System.exit调用,直接获取退出状态码
        int exitCode = catchSystemExit(() -> {
            new MailExecutor().main(args);
        });
        // 自行校验退出状态码是否符合预期
        assertEquals(0, exitCode);
        System.out.println("This is executed AFTER System.exit() method!");
    }
}

方案2:自定义安全管理器(无额外依赖,兼容低版本Java)

如果不想引入第三方依赖,可通过自定义SecurityManager拦截退出权限,注意该方案在Java 17及以上版本中已被标记为废弃,高版本Java不推荐使用:

// 在步骤类的静态初始化块中添加如下代码
static {
    System.setSecurityManager(new SecurityManager() {
        @Override
        public void checkExit(int status) {
            // 抛出自定义异常阻止进程退出,后续自行捕获处理即可
            throw new UnsupportedOperationException("拦截到System.exit调用,退出码:" + status);
        }

        @Override
        public void checkPermission(java.security.Permission perm) {
            // 放开其他所有权限避免影响正常测试逻辑
        }
    });
}

方案3:解耦业务逻辑与退出逻辑(最优解,可长期维护)

如果有权限修改被测试的XX项目代码,建议调整微入口的实现结构,将业务执行逻辑和System.exit调用拆分:

// 改造后的XX项目入口类示例
public class MailExecutor {
    // 抽离业务逻辑,直接返回执行状态码
    public static int execute(String[] args) {
        // 原有业务逻辑实现
        return 0;
    }

    public static void main(String[] args) {
        int status = execute(args);
        System.exit(status);
    }
}

测试时直接调用execute方法即可,完全不需要处理System.exit的拦截问题。

内容的提问来源于stack exchange,提问作者Alex Man

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 21:36:01