如何在Karate与Java API/类间传递值及解析响应
解决Karate与Java交互的两个问题及嵌套响应解析方案
我来帮你搞定这两个Karate和Java交互的问题,尤其是你现在遇到的嵌套Map难以解析的痛点,下面分点说明:
1. 从Karate将响应值传递给Java API
你已经通过CucumberRunner.runClasspathFeature拿到了包含响应的Map,但返回的嵌套Map结构确实不友好。这里有两种高效的处理方案:
方案一:用Karate内置工具直接查询指定字段
Karate提供了JsonPath和XmlPath工具,可以直接从嵌套结构中提取你需要的字段,无需手动遍历Map:
import com.intuit.karate.JsonPath; import com.intuit.karate.XmlPath; Map<String, Object> result = CucumberRunner.runClasspathFeature("demo/java/from-java.feature", args, true); Object responseObj = result.get("response"); // 如果是JSON响应(或Karate转成Map的XML),用JsonPath查询 String responseJson = Karate.toJson(responseObj); String city = JsonPath.read(responseJson, "$.soap:Envelope._.soap:Body._.ns1:getMbrWksMembershipDetailsResponse._.ns4:WksMembershipSummaryResponse._.ns2:customerSummary.ns2:address.ns2:city"); System.out.println(city); // 输出 SOUTH CHESTERFIELD // 如果是SOAP XML响应,转成XML字符串后用XmlPath(XPath语法)更直观 String responseXml = Karate.toXml(responseObj); String firstName = XmlPath.read(responseXml, "//ns2:firstName/text()"); System.out.println(firstName); // 输出 FRANK
方案二:转成POJO面向对象操作
如果需要多次使用多个字段,可以把嵌套Map转成JSON/XML字符串,再用Jackson(JSON)或Jackson XML模块解析成对应的POJO类:
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule; import com.fasterxml.jackson.databind.DeserializationFeature; // 1. 转成XML字符串 String responseXml = Karate.toXml(responseObj); // 2. 用Jackson XML模块解析成POJO(需先定义对应的WksMembershipSummaryResponse等类) XmlMapper xmlMapper = new XmlMapper(); xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); // 处理SOAP命名空间 xmlMapper.registerModule(new JaxbAnnotationModule()); WksMembershipSummaryResponse membershipResponse = xmlMapper.readValue(responseXml, WksMembershipSummaryResponse.class); String city = membershipResponse.getCustomerSummary().getAddress().getCity(); String lastName = membershipResponse.getCustomerSummary().getLastName();
2. 从Karate API向Java类传递值
有三种常用方式,根据你的场景选择:
方式一:在Karate Feature中直接调用Java方法传参
在feature文件里导入Java类,直接把需要的值传递给方法:# 导入你的Java类 * def MemberService = Java.type('com.yourpackage.MemberService') # 从响应中提取字段后传递 * def city = response.soap:Envelope._.soap:Body._.ns1:getMbrWksMembershipDetailsResponse._.ns4:WksMembershipSummaryResponse._.ns2:customerSummary.ns2:address.ns2:city # 调用Java方法 * def serviceResult = MemberService.updateMemberCity(city)方式二:在Feature中设置全局变量,Java端读取
在feature里把需要传递的值存入全局变量,Java端通过返回的Map获取:# 提取需要的字段并打包成对象 * def memberData = { city: response.soap:Envelope._.soap:Body._.ns1:getMbrWksMembershipDetailsResponse._.ns4:WksMembershipSummaryResponse._.ns2:customerSummary.ns2:address.ns2:city, firstName: response.soap:Envelope._.soap:Body._.ns1:getMbrWksMembershipDetailsResponse._.ns4:WksMembershipSummaryResponse._.ns2:customerSummary.ns2:firstName } # 存入全局变量 * karate.set('memberData', memberData)Java端读取:
Map<String, Object> result = CucumberRunner.runClasspathFeature("demo/java/from-java.feature", args, true); Map<String, Object> memberData = (Map<String, Object>) result.get("memberData"); String city = (String) memberData.get("city");方式三:通过运行Feature的参数传递
启动feature时传入参数,在feature里用karate.properties['key']读取,再传递给Java方法:
Java端启动时传参:Map<String, Object> args = new HashMap<>(); args.put("memberId", "12345"); CucumberRunner.runClasspathFeature("demo/java/from-java.feature", args, true);Feature里使用:
* def memberId = karate.properties['memberId'] * def MemberService = Java.type('com.yourpackage.MemberService') * def response = MemberService.getMemberDetails(memberId)
额外建议
如果可以,尽量在Karate Feature里先完成响应的字段提取,再把需要的数据传递给Java,这样避免处理复杂的嵌套结构,代码更简洁易维护。
内容的提问来源于stack exchange,提问作者Karunagara
相关产品推荐
相关产品推荐

