JUnit 内存清理让 Guava 生成测试变慢,按 engine 排除层级移除
JUnit 层级清理可触发 Vintage 生成测试的昂贵过滤。按 engine 排除层级移除仍保留 TestPlan 内部清理,应核对具体配置与实际测试结果。
启用 JUnit 的内存清理后,大量 Guava 生成测试反而明显变慢,堆栈不断出现 JUnit38ClassRunner.makeDescription 或 filter 路径,可以检查清理是否回调了 Vintage 的层级移除。不能只看到机器还有空闲核心,就认定增加线程一定有效。
具体问题出现在通过 Vintage 执行 Guava SetTestSuiteBuilder 一类生成的 JUnit 3 测试时。清理监听器在测试结束后移除 descriptor 层级,Vintage 为此重新过滤底层 runner,可能反复生成描述并走注解查找的异常路径,成本随着生成套件增加。
这里也要分清配置对象。只设置 junit.jupiter.execution.parallel.* 并没有给 Vintage 开启相同并行规则;不能把清理后的缓慢直接表述成“JUnit 关闭了所有测试并行”。先保留原引擎、套件生成方式、清理参数与堆栈,再做开关对照。
正式 JUnit 6.1.3 支持按 engine 排除这部分层级清理。需要继续清理其他引擎时,可在实际测试 classpath 的 junit-platform.properties 中合并:
junit.platform.execution.memory.cleanup.enabled=true
junit.platform.execution.memory.cleanup.engines.excluded=junit-vintage
已有排除列表时合并 engine ID,不要覆盖原设置。这些参数必须送到运行测试的 JUnit Platform,不是给任意构建器换一组同名线程池选项。使用自定义 Launcher 的项目,应检查 ConfigurationParameters 实际收到的值。
该排除项有一个重要边界:正式实现仍会从 TestPlan 移除内部标识,只跳过对应引擎 descriptor 的 removeFromHierarchy()。它没有停止所有清理,也没有改变原测试结果;因此不能把它理解成“整个 Vintage 状态永远不再释放”。引擎判断还会沿 UniqueId 从最近的 engine 段查找,套在 Suite Engine 下的 Vintage 应按最近的实际引擎归属处理。
保留原生成测试,分别运行清理关闭、全部清理,以及按 Vintage 排除的对照。检查完成用例数、失败结果与相关 filter/description 堆栈是否恢复到合理范围,并观察内存占用。不要只测一个普通 Jupiter 类,那不会进入原来的回调路径。
其他 Vintage 测试不一定有同样成本。排除会改变释放行为,是否值得采用应按当前生成套件验收,不应把所有引擎默认写进列表。若只希望给独立的大 Jupiter 任务开启清理,也可以在任务之间明确配置边界,避免影响不需要该模式的套件。
这项参数用于避开特定生成测试的昂贵层级移除。它不解决真正的业务死循环、断言慢或运行器自身保留对象;也不能保证大型套件经过一种清理配置就不会耗尽内存。升级到包含参数的版本后,应沿真实测试入口核对功能与资源两方面结果。


