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

JUnit4迁移至JUnit5触发Spark Task not serializable异常排查

问题根因

从报错栈可以直接定位到序列化失败的元凶是org.mockito.internal.junit.DefaultStubbingLookupListener:这个类是Mockito对接JUnit5时,在严格桩模式下自动给测试实例注册的内部监听器,本身没有实现序列化接口。
你的测试类实现了Serializable接口,而JUnit5默认每个测试方法创建全新的测试类实例,MockitoExtension在初始化测试实例时,会把上述不可序列化的监听器绑定到测试对象上。当你在测试类的非静态方法vcfFileAndHeaderToString中编写Spark的map转换闭包时,Spark为了把闭包分发到Executor执行,会尝试序列化闭包依赖的所有外部对象——这里就包含了当前测试类的实例,连带绑定在实例上的Mockito监听器也会被纳入序列化范围,直接触发序列化异常。
JUnit4环境下运行正常,是因为旧版Mockito针对JUnit4的Runner/Rule不会注册这个不可序列化的监听器,不存在这个额外的非序列化字段绑定。

修复方案

按优先级从高到低选择即可:

  • 方案1:将涉及Spark闭包的方法改为静态方法,切断闭包对测试类实例的引用
    把vcfFileAndHeaderToString改成静态方法,将方法依赖的SparkSession作为入参传入。静态方法不存在外部类this引用,Spark序列化闭包时不会捕获测试类实例,自然不会触发Mockito相关组件的序列化:
    private static Dataset<String> vcfFileAndHeaderToString(VCFHeaderAndRows headerAndRows, SparkSession sparkSession) {
        List<String> columns = Collections.singletonList(headerAndRows.getHeader().get(headerAndRows.getHeader().size() - 1));
        Dataset<String> columnsDS = sparkSession.sqlContext().createDataset(columns, Encoders.STRING());
        Dataset<String> rows = headerAndRows.getRows()
                .map((MapFunction<VCFRow, String>) x -> x.getRow(), Encoders.STRING());
        return columnsDS.union(rows).coalesce(1);
    }
    
    调用时传入当前的sparkSession实例即可:
    Dataset<String> result = vcfFileAndHeaderToString(exporter.runExport(defaultParameters), sparkSession);
    
  • 方案2:关闭Mockito严格桩模式,避免生成不可序列化的监听器
    通过@MockitoSettings注解将测试类的桩严格级别设置为宽松模式,Mockito就不会自动注册DefaultStubbingLookupListener:
    @ExtendWith(MockitoExtension.class)
    @MockitoSettings(strictness = Strictness.LENIENT)
    public class ExportLogicTest implements Serializable {
        // 原有业务代码无需修改
    }
    
    注意这个方案会关闭Mockito的未使用桩检测、多余调用检测能力,可能遗漏测试编写问题,优先选择方案1。
  • 方案3:将所有需要在Spark Executor端执行的闭包逻辑抽离到单独实现了Serializable接口的工具类中,不要在测试类内部定义会被分发到Executor的闭包,从根源避免测试类实例被Spark闭包捕获。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 03:49:12