BasicRobot.robotWithCurrentAwtHierarchy()多测试执行时无限冻结问题求助
问题:批量运行FEST Swing测试时无限冻结,单独运行正常
单独运行每个测试用例都能成功,但通过
mvn test批量运行所有测试时,后执行的测试会无限冻结。注释掉任意一个测试类中初始化Robot的代码后,mvn test就能正常完成,该问题在IDEA和Maven CLI中均会出现。
相关测试代码
测试类1:
import org.fest.swing.core.BasicRobot; import org.fest.swing.core.Robot; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; class RobotTest { static Robot robot; @BeforeAll static void beforeAll() { robot = BasicRobot.robotWithCurrentAwtHierarchy(); } @Test void method_ifSomething_thenShouldDoSomething() { // no actual test } }
测试类2:
// identical imports class RobotTest2 { // identical content }
依赖配置
<dependency> <groupId>org.easytesting</groupId> <artifactId>fest-swing</artifactId> <version>1.2.1</version> </dependency>
问题原因
- FEST Swing的
BasicRobot依赖AWT事件分发线程(EDT)工作,它会独占该线程资源。Maven批量测试默认在同一个JVM进程中执行所有测试,第一个测试类初始化的Robot会占用EDT,后续测试类尝试创建新Robot实例时,会因等待EDT资源陷入死锁,导致无限冻结。 - 每个测试类的
@BeforeAll是静态方法,都会执行一次BasicRobot.robotWithCurrentAwtHierarchy(),多次创建Robot实例会引发EDT的资源冲突。
解决办法
方法1:全局共享一个Robot实例
所有测试类共用同一个Robot实例,避免重复创建。可以编写一个测试基类统一管理:
import org.fest.swing.core.BasicRobot; import org.fest.swing.core.Robot; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; public abstract class BaseSwingTest { protected static Robot robot; @BeforeAll static void setupGlobalRobot() { if (robot == null) { robot = BasicRobot.robotWithCurrentAwtHierarchy(); } } @AfterAll static void teardownGlobalRobot() { if (robot != null) { robot.cleanUp(); robot = null; } } }
然后让测试类继承该基类:
import org.junit.jupiter.api.Test; class RobotTest extends BaseSwingTest { @Test void method_ifSomething_thenShouldDoSomething() { // 测试逻辑 } } class RobotTest2 extends BaseSwingTest { @Test void anotherTest() { // 测试逻辑 } }
方法2:每个测试类执行后销毁Robot
在每个测试类的@AfterAll方法中销毁Robot实例,及时释放EDT资源:
import org.fest.swing.core.BasicRobot; import org.fest.swing.core.Robot; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; class RobotTest { static Robot robot; @BeforeAll static void beforeAll() { robot = BasicRobot.robotWithCurrentAwtHierarchy(); } @AfterAll static void afterAll() { if (robot != null) { robot.cleanUp(); } } @Test void method_ifSomething_thenShouldDoSomething() { // 测试逻辑 } }
RobotTest2做同样修改,确保每个测试类执行完毕后释放资源。
方法3:让每个测试类在独立JVM运行
修改Maven Surefire插件配置,让每个测试类在单独的JVM进程中执行,彻底避免资源冲突:
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>3.2.5</version> <configuration> <forkCount>1</forkCount> <reuseForks>false</reuseForks> </configuration> </plugin> </plugins> </build>
该方法会增加测试总耗时,但能彻底解决跨测试类的资源竞争问题。
内容的提问来源于stack exchange,提问作者Sergey Zolotarev
相关产品推荐
相关产品推荐

