java.lang.AssertionError:Mockito多线程测试失败,如何禁止类并行执行?
这个问题我之前帮不少开发者解决过——本质就是并行测试时,不同测试实例的@Mock对象状态互相干扰了。因为默认每个测试方法会生成一个新的测试类实例,但并行跑的时候,你给mock设置的行为(比如when(...).thenReturn(...))会在多线程里被打乱覆盖,导致断言结果随机出错。下面给你几种针对性的解决方案,根据你的测试框架选就行:
方案1:JUnit 5 直接给测试类加串行注解
如果你的项目用的是JUnit 5(Jupiter),这是最简单直接的方式:
- 先确保你的JUnit 5依赖版本在5.3以上(这个版本开始支持并行执行特性)
- 在你的问题测试类上添加
@Execution(ExecutionMode.SAME_THREAD)注解,强制该类下所有测试方法在同一个线程串行执行,其他未标注的测试类依然可以正常并行:
import org.junit.jupiter.api.parallel.Execution; import org.junit.jupiter.api.parallel.ExecutionMode; @Execution(ExecutionMode.SAME_THREAD) public class YourProblematicTestClass { @Mock private EventDao eventDao; // 你的测试方法... }
这个注解的好处是不需要改全局配置,只针对出问题的类生效,非常灵活。
方案2:JUnit 4 结合Maven Surefire插件单独禁用并行
如果用的是JUnit 4,你可以通过Maven Surefire插件的配置,单独指定这个测试类不参与并行执行:
在项目的pom.xml中找到Surefire插件的配置块,添加classesWithSingleThreadExecution参数,填入你的测试类全限定名:
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>3.0.0-M7</version> <!-- 建议用最新稳定版 --> <configuration> <!-- 全局并行配置(比如按类并行,根据你的需求调整) --> <parallel>classes</parallel> <threadCount>4</threadCount> <!-- 指定需要单线程执行的测试类 --> <classesWithSingleThreadExecution> <param>com.yourpackage.YourProblematicTestClass</param> </classesWithSingleThreadExecution> </configuration> </plugin> </plugins> </build>
这样全局其他测试类依然可以并行跑,只有你指定的这个类会被强制单线程执行。
方案3:Spring Boot测试额外优化(如果是Spring环境)
如果你的测试是Spring Boot测试(用到了@SpringBootTest),除了上面的串行方案,你也可以考虑把@Mock换成@MockBean——@MockBean是Spring容器管理的mock对象,默认每个测试方法会重新初始化上下文(如果没开上下文缓存的话),能减少部分干扰。不过最稳妥的还是前面的串行执行方案,毕竟你的每个测试mock行为都不一样,串行能彻底避免多线程的状态混乱。
设置完成后,你可以在远程服务器上跑测试时,观察该类的测试日志,确认它们是按顺序执行的,而不是并行启动,这样就能解决断言随机失败的问题了。
内容的提问来源于stack exchange,提问作者michealAtmi

