Karate Netty Mock服务Schema匹配规则不生效问题及解决方案
问题背景
当前使用Karate 1.1.0版本构建支持可选请求对象的Mock服务:请求载荷中beneficiary节点下可二选一传入cardInfo对象(含number字段)或cardTokenInfo对象(含token字段),两种合法请求结构示例如下:
"beneficiary":{ "cardInfo":{ "number": "12345" } }
"beneficiary":{ "cardTokenInfo":{ "token": "98765" } }
初始实现代码如下:
Feature: Karate netty - testing for optional. The request payload may have either benefiaciary.cardInfo object or beneficiary.cardTokenInfo object Background: * def happyPathResponse_json = {status: 'Payment accepted'} * def invalidResponse_json = {status: 'Invalid request'} ## Happy path if cardNumber is passed Scenario: pathMatches('/mock/payment/v5') && request.beneficiary.cardInfo.number == '12345' * def response = happyPathResponse_json * def responseStatus = 201 * def responseHeaders = {'Content-Type': 'application/json'} ## Happy path if card token is passed Scenario: pathMatches('/mock/payment/v5') && request.beneficiary.cardTokenInfo.number == '98765' * def response = happyPathResponse_json * def responseStatsus = 201 * def responseHeaders = {'Content-Type':'application/json'} ## Catch all scenario if nothing matches Scenario: pathMatches('/mock/payment/v5') * def response = invalidRespose_json * def responseStatus = 201 * def responseHeaders = {'Content-Type': 'application/json'}
问题现象
传入携带beneficiary.cardInfo的请求时逻辑可正常运行,但传入携带beneficiary.cardTokenInfo的请求时,Karate Netty服务抛出错误:
Cannot read property "number" from undefined
原因分析
该报错符合预期:第一个场景的匹配逻辑会直接读取不存在的cardInfo节点下的number属性,导致流程中断无法进入后续场景。
最初尝试在场景匹配条件中加入Schema校验逻辑,判断当beneficiary.cardInfo == '#present'时才匹配对应场景,代码如下:
Scenario: pathMatches('/mock/payment/v5') && request.beneficiary.cardInfo == '#present' && request.beneficiary.cardInfo.number == '12345' * def response = happyPathResponse_json * def responseStatus = 201 * def responseHeaders = {'Content-Type': 'application/json'}
但该Schema匹配写法仅在普通Karate测试用例中可正常生效,在Netty Mock服务中始终返回false无法匹配。* if() karate.abort()方案不适用,该写法会终止当前Feature执行,导致后续场景无法运行。
后续排查中尝试使用bodyPath方法实现路径安全读取,将request.beneficiary.cardInfo.number == '12345'替换为bodyPath('$.beneficiary.cardInfo.number') == '12345'后可解决路径不存在的报错问题,但'#present'标记仍无法正常使用。
可行解决方案
Mock场景匹配条件仅支持原生JS逻辑,共有两种可落地的修复方案:
- 方案1:使用
bodyPath方法做安全路径取值匹配,直接读取JSON路径值做判断,不存在的路径会返回null不会抛出异常Scenario: pathMatches('/mock/payment/v5') && bodyPath('$.beneficiary.cardInfo.number') == '12345' * def response = happyPathResponse_json * def responseStatus = 201 * def responseHeaders = {'Content-Type': 'application/json'} - 方案2:通过
karate.match方法先判断字段是否存在,再做值匹配Scenario: pathMatches('/mock/payment/v5') && karate.match("request.beneficiary.cardInfo == '#present'").pass && request.beneficiary.cardInfo.number == '12345' * def response = happyPathResponse_json * def responseStatus = 201 * def responseHeaders = {'Content-Type': 'application/json'}
避坑提示
网传直接使用request.beneficiary.cardInfo.number.contains('12345')的写法存在缺陷,当请求传入cardInfo下的未知字段时会直接触发报错,异常请求示例如下:
"beneficiary":{ "cardInfo":{ "someUnknownKey": "12345" } }
内容的提问来源于stack exchange,提问作者Dinesh Arora

