在我的Citrus测试中,我正在尝试验证嵌入在JSON文档中的XML消息(WireMock的输出)。需要解析XML文本,因为它包含我想忽略的时间戳。 JSON消息的XML部分如下所示:
"requests": [
{
"id": "52844d5a-59de-4288-8000-7f48fcda41e5",
"request": {
"body": "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"> [content omitted] </soapenv:Body></soapenv:Envelope>",
}
]
这是我的Java测试代码:
http()
.client(wiremockClient)
.receive()
.response(HttpStatus.OK)
.messageType(MessageType.JSON)
.extractFromPayload("$.requests[0].request.body", "body")
.payload(new ClassPathResource("output/esb/add_conf_to_cart/response2.xml"))
;
其中respon2.xml仅包含XML文本(上面显示的JSON消息中的“body”的内容),而我从Citrus获得的错误是
com.consol.citrus.exceptions.CitrusRuntimeException: Failed to parse JSON text
…
Caused by: net.minidev.json.parser.ParseException: Unexpected token <soapenv:Envelope xmlns:soapenv=
那么,如何验证JSON文档中嵌入的XML?
答案 0 :(得分:1)
我对你目前的解决方案有两点评论:
extractFromPayload(..)
将您JSON的body
部分提取到名为body
的Citrus变量中。这与payload(..)
部分没有任何关系。您刚刚将body
的JSON内容存储到Citrus变量body
中。您可能会或可能不会意识到这一点
payload(..)
方法将始终验证收到的整个有效负载,即整个JSON对象。
如果您只想验证部分回复,请使用JSON Path validation:.validate("$.some.json.path", "someValue")
Citrus提供了完全符合您用例的内部方法,请参阅matchesXml()的文档。
这是最简单的解决方案:
http()
.client(wiremockClient)
.receive()
.response(HttpStatus.OK)
.messageType(MessageType.JSON)
.validate("$.requests[0].request.body", @matchesXml('citrus:readFile('classpath:output/esb/add_conf_to_cart/response2.xml')')@)
在您的情况下,您只需匹配整个JSON结构并将方法@matchesXml('<some><validation_xml></some></validation_xml>')@
放在正确的JSON条目中:
http()
.client(wiremockClient)
.receive()
.response(HttpStatus.OK)
.messageType(MessageType.JSON)
.payload("{\n"+
" \"requests\": {\n"+
" \"id\": \"52844d5a-59de-4288-8000-7f48fcda41e5\",\n"+
" \"request\": {\n"+
" \"body\": \"@matchesXml('<soapenv:Envelope xmlns:soapenv=\\\"http://schemas.xmlsoap.org/soap/envelope/\\\"> [content omitted] </soapenv:Body></soapenv:Envelope>')@\"\n"+
" }\n"+
" }\n"+
"}");
payload
的字符串必须是有效的JSON,即必须转义JSON值中的引号。\\\"
payload
字符串解析为JSON,并将其作为JSON对象保留在内部,其中转义的引号未转义。然后它将此String传递给验证函数matchesXml
。</soapenv:Body>
\"
citrus:readFile()
功能payload
,您仍需要在XML中转义引号。您可以使用citrus:translate()
:citrus:translate('citrus:readFile('classpath:some/path/to/response.xml')', '\"', '\\"')
创建文件response_validation.json
:
{
"requests": {
"id": "52844d5a-59de-4288-8000-7f48fcda41e5",
"request": {
"body": "@matchesXml('${jsonEscapedXmlInput}')@"
}
}
}
在您的测试用例中,创建Citrus变量jsonEscapedXmlInput
,该变量读取并转义XML文件:
variable("jsonEscapedXml", "citrus:translate('citrus:readFile('classpath:output/esb/add_conf_to_cart/response2.xml')', '\\\"', '\\\\\"')")
然后使用它
http()
.client(wiremockClient)
.receive()
.response(HttpStatus.OK)
.messageType(MessageType.JSON)
.payload(new ClassPathResource("classpath:validation/response_validation.json"))
;
答案 1 :(得分:0)
使用gucce的解决方案我终于找到了验证XML的正确语法。代码现在看起来像这样:
variable("jsonXml", "'citrus:readFile('classpath:output/esb/add_conf_to_cart/response2.xml')'");
http()
.client(wiremockClient)
.send()
.get("/__admin/requests")
.accept("application/json");
HttpClientResponseActionBuilder body = http()
.client(wiremockClient)
.receive()
.response(HttpStatus.OK)
.messageType(MessageType.JSON)
.validate("$.requests[0].request.body", "@matchesXml(${jsonXml})@")
;
我犯的错误首先是忘记第二个@然后在参数中添加单引号到matchesXML。所以
.validate("$.requests[0].request.body", "@matchesXml('${jsonXml}')@")
无效,但
.validate("$.requests[0].request.body", "@matchesXml(${jsonXml})@")
将完成这项工作。
答案 2 :(得分:0)
另一种解决方案使用AbstractTestAction的实现来调用在Citrus上下文中进行验证的方法:
http()
.client(wiremockClient)
.receive()
.response(HttpStatus.OK)
.messageType(MessageType.JSON)
.extractFromPayload("$.requests[0].request.body", "body")
;
action(action(new DummyAction(new File(EXPECTED_OUTPUT_FILE)));
action()调用注册DummyAction以执行验证。在我的情况下,它需要一个文件来验证通过http()从有效负载中提取的正文的内容.extractFromPayload(&#34; $。requests [0] .request.body&#34;,&#34; body& #34)
Class DummyAction看起来像这样:
class DummyAction extends AbstractTestAction {
private File expectedOutputFile;
public DummyAction(File expectedOutputFile) {
this.expectedOutputFile = expectedOutputFile;
}
@Override
public void doExecute(TestContext testContext) {
String body = testContext.getVariable("body");
Assert.assertTrue(body.startsWith("<soapenv:Envelope "), "Request should start with '<soapenv:Envelope '");
}
}
doExecute()可以访问测试上下文中可用的变量。所以extractFromPayload()放置一个名为&#39; body&#39;的变量。在稍后在doExecute()中访问的上下文中。 这个解决方案允许运行任意Java代码,在我的例子中,从SOAP信封中提取XML文档,隐藏在JSON文档中。