Karate MasterRunner运行报PolyglotException单场景执行正常
问题现象
在使用Karate 1.1.0版本开展自动化测试时,通过MasterTestRunner主运行器执行测试(配置项:并行度为1、输出Cucumber JSON与JUnit XML报告、绑定ExtentReport钩子、筛选@test标签用例),调用utils类静态方法returnIds时抛出异常。
异常堆栈
org.graalvm.polyglot.PolyglotException: java.lang.AssertionError com.oracle.truffle.polyglot.PolyglotList$Cache.lookup(PolyglotList.java:180) com.oracle.truffle.polyglot.PolyglotList.<init>(PolyglotList.java:73) com.oracle.truffle.polyglot.PolyglotList.create(PolyglotList.java:96) com.oracle.truffle.polyglot.PolyglotHostAccess.toList(PolyglotHostAccess.java:107) com.oracle.truffle.host.HostToTypeNode.asJavaObject(HostToTypeNode.java:384) com.oracle.truffle.host.HostToTypeNode.convertImpl(HostToTypeNode.java:194) com.oracle.truffle.host.HostToTypeNode.doCached(HostToTypeNode.java:118)
关联代码与配置
主运行器代码
package tests; import com.intuit.karate.Results; import com.intuit.karate.Runner; import net.masterthought.cucumber.Configuration; import net.masterthought.cucumber.ReportBuilder; import org.apache.commons.io.FileUtils; import org.junit.jupiter.api.Test; import reporting.ExtentReport; import java.io.File; import java.util.ArrayList; import java.util.Collection; import static org.junit.jupiter.api.Assertions.assertEquals; class MasterTestRunner { // this will run all *.feature files /*@Karate.Test Karate testAll() { return Karate.run().relativeTo(getClass()); }*/ //Karate Parallel Runner @Test public void testParallel() { final Results results = Runner.path("classpath:tests/features").hook(new ExtentReport()).tags("@test") .outputCucumberJson(true).outputJunitXml(true).parallel(1); assertEquals(0, results.getFailCount(), results.getErrorMessages()); } //Boiler Plate for Cucumber report generation public static void generateReport(final String karateOutputPath) { final Collection<File> jsonFiles = FileUtils.listFiles(new File(karateOutputPath), new String[]{"json"}, true); final ArrayList<String> jsonPaths = new ArrayList<>(jsonFiles.size()); jsonFiles.forEach(file -> jsonPaths.add(file.getAbsolutePath())); final Configuration config = new Configuration(new File("target"), "Karate test"); System.out.println("config report " + config.getBuildNumber()); final ReportBuilder reportBuilder = new ReportBuilder(jsonPaths, config); reportBuilder.generateReports(); } }
问题特征
- 异常仅在通过主运行器执行时触发,单独运行对应feature文件时用例可正常执行、无报错。
测试Feature文件内容
Feature: karate testing @test Scenario: Karate test case * def acts = [ { "label": "BUSINESS","name": "David","id": "u374892","type": "DIVISION"},{"label": "Division","name":"MILLER","id": "u236478","type": "BUSINESS"}] * def data1 = [{"UserName": "ABENANTE","UserID": "u109238","Role": "BUSINESS"},{"UserName": "Louis","UserID": "u784784","Role": "DIVISION"}] * def desk = utils.returnIds(data1, 2, acts, "DESK") * print desk
Java工具方法签名
public static List<Map<String, Object>> returnIds(List<Map<String, Object>> listOfAllIds, int numberOfIds, List<Map<String, Object>> listOfIds, String role)
Maven依赖配置
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> <maven.compiler.version>3.6.0</maven.compiler.version> <karate.version>1.1.0</karate.version> </properties> <dependencies> <!-- For Karate Begin --> <dependency> <groupId>com.intuit.karate</groupId> <artifactId>karate-junit5</artifactId> <version>${karate.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>com.intuit.karate</groupId> <artifactId>karate-gatling</artifactId> <version>${karate.version}</version> <scope>test</scope> </dependency> </dependencies>
排查思路与解决方案
- 根因定位:该问题是Karate 1.1.0版本内置GraalVM引擎的已知bug。单独运行Feature时走单例非并行执行上下文,JS数组转Java List的类型转换缓存可正常命中;通过
parallel()方法启动运行器时(哪怕并行度设置为1),会走隔离上下文执行逻辑,GraalVM的PolyglotList缓存校验逻辑存在缺陷,触发AssertionError。 - 优先修复方案:直接升级Karate版本到1.2.0及以上稳定版本,官方已在后续版本修复该GraalVM类型转换缓存异常问题。
- 临时规避方案(无法升级版本时可选用):
- 入参提前转换:调用Java静态方法前,手动将Feature中定义的JS数组转为原生Java List,绕开GraalVM自动类型转换逻辑,示例代码:
* def ArrayList = Java.type('java.util.ArrayList') * def data1 = ArrayList.from(data1) * def acts = ArrayList.from(acts) * def desk = utils.returnIds(data1, 2, acts, "DESK") - 调整方法入参类型:修改Java工具方法的入参定义,将强类型
List<Map<String, Object>>改为通用Object类型,在方法内部自行完成类型判断与转换,避开GraalVM自动泛型类型匹配转换逻辑。 - 钩子兼容性校验:临时移除绑定的ExtentReport自定义钩子后重试,部分自定义实现的Karate钩子会错误修改GraalVM宿主访问配置,触发类型转换异常。
- 入参提前转换:调用Java静态方法前,手动将Feature中定义的JS数组转为原生Java List,绕开GraalVM自动类型转换逻辑,示例代码:
- 依赖冲突排查:执行
mvn dependency:tree查看依赖树,排查是否存在手动引入的、与Karate内置版本不一致的GraalVM、Truffle相关依赖,存在冲突时直接排除多余依赖即可。
内容的提问来源于stack exchange,提问作者cody
相关产品推荐
相关产品推荐

