如何解决Selenium与TestNG代码中的java.util.ConcurrentModificationException错误
解决TestNG & Selenium中的
ConcurrentModificationException错误 这个问题我之前帮同事排查过,你遇到的TestNG里关联JUnitReportReporter的ConcurrentModificationException,还有Selenium代码里的同类错误,本质都是在遍历集合的同时修改了集合结构,下面分场景给你具体的解决办法:
一、TestNG报告器报错的处理方案
1. 优先升级TestNG版本
旧版本的TestNG(比如6.x部分版本)在JUnitReportReporter模块存在并发bug,当测试线程和报告生成线程同时操作测试结果集合时就会触发这个异常。升级到7.x以上的稳定版本就能解决这个问题:
- 如果用Maven,修改pom.xml依赖:
<dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>7.8.0</version> <scope>test</scope> </dependency>
- 如果用Gradle,修改build.gradle:
testImplementation 'org.testng:testng:7.8.0'
2. 临时禁用JUnitReportReporter
如果暂时不想升级版本,可以直接在TestNG的配置文件里去掉这个报告生成器,改用TestNG自带的其他报告工具(比如HTML报告、可邮件发送的报告):
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd" > <suite name="YourTestSuite"> <listeners> <!-- 注释掉有问题的JUnitReportReporter --> <!-- <listener class-name="org.testng.reporters.JUnitReportReporter"/> --> <!-- 保留你需要的其他监听器 --> <listener class-name="org.testng.reporters.HtmlReporter"/> <listener class-name="org.testng.reporters.EmailableReporter"/> </listeners> <test name="YourTest"> <classes> <class name="demotestng2.YourTestClass"/> </classes> </test> </suite>
3. 检查测试代码中的共享集合操作
如果你的测试代码里自己维护了共享集合(比如在@BeforeMethod/@AfterMethod和测试方法中同时读写),要改用线程安全的集合(比如CopyOnWriteArrayList代替普通ArrayList),或者在操作集合时加同步锁:
// 替换普通ArrayList为线程安全的CopyOnWriteArrayList private List<String> sharedTestData = new CopyOnWriteArrayList<>(); @BeforeMethod public void setUp() { // 此时操作集合不会触发并发修改异常 sharedTestData.add("test data"); }
二、Selenium代码中同类错误的处理方案
Selenium里的ConcurrentModificationException通常出现在遍历页面元素集合时,元素因操作(比如点击删除)从DOM中移除,导致集合结构被修改。解决办法有两种:
1. 使用迭代器的remove()方法
迭代器本身支持在遍历过程中安全修改集合:
List<WebElement> elements = driver.findElements(By.tagName("div")); Iterator<WebElement> elemIterator = elements.iterator(); while (elemIterator.hasNext()) { WebElement elem = elemIterator.next(); if (elem.getText().trim().isEmpty()) { elem.click(); // 操作导致元素从DOM移除 elemIterator.remove(); // 用迭代器的remove方法同步修改集合 } }
2. 先将集合转成新的副本再遍历
把元素集合复制到一个新的集合中,遍历副本就不会受原集合修改的影响:
List<WebElement> elements = driver.findElements(By.tagName("div")); // 遍历集合的副本 for (WebElement elem : new ArrayList<>(elements)) { if (elem.getText().trim().isEmpty()) { elem.click(); } }
内容的提问来源于stack exchange,提问作者Akir
相关产品推荐
相关产品推荐

