Karate中数组时而为数组时而转为对象的问题求助
问题分析与解决方案
这个问题的核心是JavaScript数组与Karate原生列表的类型差异,导致在不同赋值场景下表现不一致,进而引发断言失败。让我们一步步拆解原因并给出解决办法:
为什么会出现这个现象?
当你使用#(arr2)在JSON字面量中嵌入数组时,Karate会对JS函数返回的JavaScript数组进行序列化处理——此时JS数组会被当作普通对象,把索引作为键转换为键值对结构(也就是你看到的{"0": {...}, "1": {...}}形式)。而copy命令会触发Karate的类型转换逻辑,自动将这种键值对结构转回Karate原生的列表类型,所以yy.aa恢复成了数组,最终导致xx和yy的aa字段类型/结构不匹配,断言失败。
解决办法
这里提供三种可行的方案,你可以根据自己的需求选择:
方案1:直接使用Karate原生的列表拼接
其实Karate本身支持列表直接相加,完全不需要额外写JS函数!你可以直接替换成:
Feature: Scenario: * def arr = [{a: 'a'}, {b: 'b'}, {c: 'c'}] * def arr1 = [{a: 'a'}, {b: 'b'}, {c: 'c'}] * def arr2 = arr + arr1 // 原生列表拼接,一步到位 * print 'arr2', arr2 * def xx = { aa: arr2 } * print 'xx', xx * copy yy = xx * print 'yy', yy * match xx == yy
这样得到的arr2是Karate原生列表,无论怎么赋值都能保持正确的数组结构,断言自然会通过。
方案2:修改JS函数返回Karate可识别的列表类型
如果必须保留JS函数的逻辑,你可以在函数末尾将JS数组转换为Java的List类型(Karate对Java集合有很好的支持):
function(lists){ var arr = []; for each (var list in lists){ for each (var item in list){ arr.push(item); } } return Java.to(arr, 'java.util.List'); // 转换为Java列表 }
修改后,JS函数返回的是Karate能直接识别的列表类型,此时无论用#(arr2)还是直接赋值,都能保持数组结构。
方案3:避免用#()嵌入数组,直接引用变量
在定义对象xx时,不要用#(arr2)的表达式嵌入方式,直接引用变量即可:
Feature: Scenario: * def appendList = read('../utils/append-list.js') * def arr = [{a: 'a'}, {b: 'b'}, {c: 'c'}] * def arr1 = [{a: 'a'}, {b: 'b'}, {c: 'c'}] * def arr2 = appendList([arr, arr1]) * print 'arr2', arr2 * def xx = { aa: arr2 } // 直接引用变量,而非#()嵌入 * print 'xx', xx * copy yy = xx * print 'yy', yy * match xx == yy
这种方式下,Karate会直接保留JS数组的原始类型(或自动转换为原生列表),不会触发错误的序列化,xx.aa和yy.aa会保持一致。
内容的提问来源于stack exchange,提问作者PhuongLM
相关产品推荐
相关产品推荐

