Java 如何使用Citrus框架验证JSON中嵌入的XML?
在我的Citrus测试中,我试图验证嵌入JSON文档(WireMock的输出)中的XML消息。需要解析XML文本,因为它包含我想忽略的时间戳。JSON消息的XML部分如下所示:Java 如何使用Citrus框架验证JSON中嵌入的XML?,java,json,xml,citrus-framework,Java,Json,Xml,Citrus Framework,在我的Citrus测试中,我试图验证嵌入JSON文档(WireMock的输出)中的XML消息。需要解析XML文本,因为它包含我想忽略的时间戳。JSON消息的XML部分如下所示: "requests": [ { "id": "52844d5a-59de-4288-8000-7f48fcda41e5", "request": { "body": "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.o
"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>",
}
]
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})@")
;
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 '");
}
}
其中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=
com.consol.citrus.exceptions.CitrusRuntimeException:无法解析JSON文本
…
原因:net.minidev.json.parser.ParseException:意外的令牌澄清
关于你目前的解决方案,我有两点意见:
extractFromPayload(..)
将JSON的body
部分提取到一个名为body
的文件中。这与有效负载(…)
部分无关。您刚刚将body
的JSON内容存储到一个柑橘变量body
中。你可能知道,也可能不知道
payload(…)
方法将始终验证接收到的整个有效负载,即整个JSON对象
如果您只想验证响应的一部分,请使用:.validate(“$.some.json.path”,“someValue”)
解决方案
Citrus为您的用例提供了一个内部方法,有关详细信息,请参阅文档
仅验证XML结构
这是最简单的解决方案:
http()
.客户(wiremockClient)
.receive()
.响应(HttpStatus.OK)
.messageType(messageType.JSON)
.validate($.requests[0].request.body“,@matchesXml('classpath:readFile('classpath:output/esb/add_conf_to_cart/response2.xml'))@)
验证整个JSON响应
在您的例子中,只需匹配整个JSON结构,并将方法@matchesXml(“”)@
放入正确的JSON条目中:
http()
.客户(wiremockClient)
.receive()
.响应(HttpStatus.OK)
.messageType(messageType.JSON)
.payload(“{\n”+
“\”请求\“:{\n”+
“id\:\“52844d5a-59de-4288-8000-7f48fcda41e5\,\n”+
“\”请求\“:{\n”+
“\“body\:\”@matchesXml(“[内容省略]”)@\”\n”+
“}\n”+
“}\n”+
"}");
评论
- 放入
payload
的字符串必须是有效的JSON,即JSON值中的引号必须转义
- Java字符串中的引号也必须转义,因此我们必须编写
\\\”
- Citrus首先将
有效负载
字符串解析为JSON,并将其作为JSON对象保存在内部,其中转义引号未被转义。然后将该字符串传递给验证函数匹配XML
- 您当前的示例不是有效的XML,因为标记
从未打开
- 将有效负载请求放在单独的文件中要容易得多,只需注意该文件仍然必须是有效的JSON,即引号必须用反斜杠转义,如so
\“
- 您可能希望从单独的文件中读取XML内容。在这种情况下,您可以使用柑橘的功能
- 对于
负载
,仍然需要在XML中转义引号。您可以使用:citrus:translate('citrus:readFile('classpath:some/path/to/response.xml')、“\”、“\\”)执行此操作。
- 转义是非常棘手的,因为我们处理的是引号和反斜杠,这在Java、JSON和XML中是特殊的
- 其工作应如下:
创建一个文件response\u validation.json
:
{
“请求”:{
“id”:“52844d5a-59de-4288-8000-7f48fcda41e5”,
“请求”:{
“正文”:“@matchesXml('${jsonEscapedXmlInput}')@”
}
}
}
在您的测试用例中,创建柑橘变量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"))
;
澄清
关于你目前的解决方案,我有两点意见:
extractFromPayload(..)
将JSON的body
部分提取到一个名为body
的文件中。这与有效负载(…)
部分无关。您刚刚将body
的JSON内容存储到一个柑橘变量body
中。你可能知道,也可能不知道
payload(…)
方法将始终验证接收到的整个有效负载,即整个JSON对象
如果您只想验证响应的一部分,请使用:.validate(“$.some.json.path”,“someValue”)
解决方案
Citrus为您的用例提供了一个内部方法,有关详细信息,请参阅文档
仅验证XML结构
这是最简单的解决方案:
http()
.客户(wiremockClient)
.receive()
.响应(HttpStatus.OK)
.messageType(messageType.JSON)
.validate($.requests[0].request.body“,@matchesXml('classpath:readFile('classpath:output/esb/add_conf_to_cart/response2.xml'))@)
验证整个JSON响应
在您的例子中,只需匹配整个JSON结构,并将方法@matchesXml(“”)@
放入正确的JSON条目中:
http()
.客户(wiremockClient)
.receive()
.响应(HttpStatus.OK)
.messageType(messageType.JSON)
.payload(“{\n”+
“\”请求\“:{\n”+
“id\:\“52844d5a-59de-4288-8000-7f48fcda41e5\,\n”+
“\”请求\“:{\n”+
“\“body\:\”@matchesXml(“[内容省略]”)@\”\n”+
“}\n”+
“}\n”+
"}");
评论
- 放入
payload
的字符串必须是有效的JSON,即JSON值中的引号必须转义
- Java字符串中的引号也必须转义,因此我们必须编写
\\\”
- Citrus首先将
有效负载
字符串解析为JSON,并将其作为JSON对象保存在内部,其中转义引号未被转义。然后将该字符串传递给验证函数匹配XML
- 你的狗
.validate("$.requests[0].request.body", "@matchesXml('${jsonXml}')@")
.validate("$.requests[0].request.body", "@matchesXml(${jsonXml})@")
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)));
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 '");
}
}