将 JDBC 响应与 XML 节点数量不同且顺序可能发生变化的响应进行比较?
Compare JDBC Response to an XML Response where number of nodes vary and order could change?
我对编码还很陌生,在尝试将 JDBC 查询的结果与 XML 响应的结果进行比较时遇到了一些麻烦。
我使用的是 groovy 而不是 SoapUI 中内置的 XPATH,因为根据我请求中传递的参数,返回的节点数量可能会有所不同,我需要验证所有这些节点。
我使用我发现的各种示例构建了下面的脚本,因为我找不到一个可以执行我想要的操作的示例。我将 class 标记中的所有内容插入到 Eclipse 中,但它没有检测到任何语法错误。但是,当我 运行 SoapUI 中的脚本到达解析 xml 响应的部分时,没有构建任何内容。那么我的验证和断言当然会失败。 JDBC 数据构建得很好。
在此先感谢您的帮助。
import com.eviware.soapui.support.XmlHolder
import groovy.xml.XmlUtil
import groovy.util.XmlSlurper
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context)
class Model {
def campaignSysKey
def campaignName
def startDate
def endDate
def campaignCode
def buildJdbcData(row) {
row.with {
campaignSysKey = UPGRADETYPE
campaignName = SOURCEDESC
startDate = STARTDATE
endDate = ENDDATE
campaignCode = SOURCECODE
}
}
def buildXMLData(tagInfo) {
campaignSysKey = tagInfo.@campaignSysKey
campaignName = tagInfo.@campaignName
startDate = tagInfo.@startDate
endDate = tagInfo.@endDate
campaignCode = tagInfo.@campaignCode
}
}
def jdbcResponse = context.expand('${Validation#ResponseAsXml}')
def xmlResponse = context.expand('${OfferHistoryRequest#Response}')
def results = new XmlSlurper().parseText(jdbcResponse)
def jdbcDataObjects = []
results.ResultSet.Row.each { row ->
jdbcDataObjects.add(new Model().buildJdbcData(row))
}
def arrayOfTagInfo = new XmlSlurper().parseText(xmlResponse)
def xmlDataObjects = []
arrayOfTagInfo.TagInfo.each { tagInfo ->
xmlDataObjects.add(new Model().buildXMLData(tagInfo))
}
log.info "${jdbcDataObjects.size()}"
log.info "${xmlDataObjects.size()}"
if (jdbcDataObjects.size() != xmlDataObjects.size()) {
log.info("Jdbc resultset size is : ${jdbcDataObjects.size()} and XML result size is : ${xmlDataObjects.size()}")
}
assert jdbcDataObjects == xmlDataObjects, "Comparison of JDBC and XML data is failed"
JDBC 响应结构:
<Results>
<ResultSet fetchSize="0">
<Row rowNumber="1">
<UPGRADETYPE>1</UPGRADETYPE>
<SOURCEDESC>Desc 1</SOURCEDESC>
<STARTDATE>2015-01-01</STARTDATE>
<ENDDATE>2017-12-31</ENDDATE>
<SOURCECODE>ABC123</SOURCECODE>
</Row>
<Row rowNumber="2">
<UPGRADETYPE>2</UPGRADETYPE>
<SOURCEDESC>Desc 2</SOURCEDESC>
<STARTDATE>2015-01-01</STARTDATE>
<ENDDATE>2017-12-31</ENDDATE>
<SOURCECODE>XYZ987</SOURCECODE>
</Row>
</ResultSet>
</Results>
XML 响应(有意删除了 Holding 标签之间的数据,但保留它们以显示响应结构。我只关心 Campaign 节点):
<soap:Envelope xmlns:soap="http://sample.org">
<soap:Body>
<TXLife xmlns="http://sample.org">
<TXLifeResponse>
<TransRefGUID>123456</TransRefGUID>
<TransType tc="999"/>
<TransSubType tc="9909"/>
<BusinessService DataRep="VIEW"/>
<TransExeDate>2017-01-19-05:00</TransExeDate>
<TransExeTime>09:19:30.668-05:00</TransExeTime>
<StartRecord>1</StartRecord>
<TransResult>
<ResultCode tc="1"/>
<RecordsFound>2</RecordsFound>
</TransResult>
<OLifE>
<Holding id="Holding_B1234567">
</Holding>
<Campaign id="Campaign_B1234567_1" AppliesToCoverageID="Coverage_B1234567_1">
<CampaignSysKey>1</CampaignSysKey>
<CampaignName>Desc 1</CampaignName>
<StartDate>2015-01-01</StartDate>
<EndDate>2017-12-31</EndDate>
<CampaignCode>ABC123</CampaignCode>
</Campaign>
<Campaign id="Campaign_B1234567_2" AppliesToCoverageID="Coverage_B1234567_2">
<CampaignSysKey>2</CampaignSysKey>
<CampaignName>Desc 2</CampaignName>
<StartDate>2015-01-01</StartDate>
<EndDate>2017-12-31</EndDate>
<CampaignCode>XYZ987</CampaignCode>
</Campaign>
</OLifE>
</TXLifeResponse>
</TXLife>
</soap:Body>
</soap:Envelope>
来自 SoapUI 日志的错误:
Thu Jan 19 10:00:31 EST 2017:ERROR:java.lang.AssertionError: Comparison of JDBC and XML data is failed. Expression: (jdbcDataObjects == xmlDataObjects). Values: jdbcDataObjects = [X34143, X33582], xmlDataObjects = []
java.lang.AssertionError: Comparison of JDBC and XML data is failed. Expression: (jdbcDataObjects == xmlDataObjects). Values: jdbcDataObjects = [X34143, X33582], xmlDataObjects = []
at org.codehaus.groovy.runtime.InvokerHelper.assertFailed(InvokerHelper.java:404)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.assertFailed(ScriptBytecodeAdapter.java:650)
at Script5.run(Script5.groovy:67)
at com.eviware.soapui.support.scripting.groovy.SoapUIGroovyScriptEngine.run(SoapUIGroovyScriptEngine.java:92)
at com.eviware.soapui.support.scripting.groovy.SoapUIProGroovyScriptEngineFactory$SoapUIProGroovyScriptEngine.run(SoapUIProGroovyScriptEngineFactory.java:79)
at com.eviware.soapui.impl.wsdl.teststeps.WsdlGroovyScriptTestStep.run(WsdlGroovyScriptTestStep.java:156)
at com.eviware.soapui.impl.wsdl.panels.teststeps.GroovyScriptStepDesktopPanel$RunAction.run(GroovyScriptStepDesktopPanel.java:274)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
这是我修改过的脚本。
您制作并解决的脚本中的问题如下 -
- xml 元素读取不正确
- 使方法静态化
- 规范注释添加到 class 以便它可以进行比较
Groovy 脚本
//Class to model the different sources of data and create object
//so that those are comparable
@groovy.transform.Canonical
class Model {
String campaignSysKey
String campaignName
String startDate
String endDate
String campaignCode
static def buildJdbcData(row) {
def obj = new Model()
row.with {
obj.campaignSysKey = UPGRADETYPE
obj.campaignName = SOURCEDESC
obj.startDate = STARTDATE
obj.endDate = ENDDATE
obj.campaignCode = SOURCECODE
}
obj
}
static def buildXMLData(cmpgn) {
def obj = new Model()
obj.campaignSysKey = cmpgn.CampaignSysKey as String
obj.campaignName = cmpgn.CampaignName as String
obj.startDate = cmpgn.StartDate as String
obj.endDate = cmpgn.EndDate as String
obj.campaignCode = cmpgn.CampaignCode as String
obj
}
}
//Read the jdbc response from its step
def jdbcResponse = context.expand('${Validation#ResponseAsXml}')
//Read the xml response from its step
def xmlResponse = context.expand('${OfferHistoryRequest#Response}')
//Read & Create objects for jdbc response
def results = new XmlSlurper().parseText(jdbcResponse)
def jdbcDataObjects = []
results.ResultSet.Row.each { row ->
jdbcDataObjects.add(Model.buildJdbcData(row))
}
//Read & Create objects for xml response
def parsedXml = new XmlSlurper().parseText(xmlResponse)
def campaigns = parsedXml.'**'.findAll{it.name() == 'Campaign'}
def xmlDataObjects = []
campaigns.each { cmpgn ->
xmlDataObjects.add(Model.buildXMLData(cmpgn))
}
//Log both responses
log.info "Jdbc response records: ${jdbcDataObjects.size()}"
log.info "Xml response records: ${xmlDataObjects.size()}"
if (jdbcDataObjects.size() != xmlDataObjects.size()) {
log.info("Jdbc resultset size is : ${jdbcDataObjects.size()} and XML result size is : ${xmlDataObjects.size()}")
}
//Check if both object sizes are equal before comparing one to one
assert jdbcDataObjects.size() == xmlDataObjects.size(), "Both responses have not matched element count"
//Log both the objects
log.info jdbcDataObjects.toString()
log.info xmlDataObjects.toString()
//Compare now both the responses and show the difference
if (jdbcDataObjects != xmlDataObjects){
log.info "Both responses do not match"
for(int index=0;index<jdbcDataObjects.size();index++){
assert jdbcDataObjects[index] == xmlDataObjects[index], "Responses @ ${index+1} position do not match"
}
} else {
log.info "Both responses matches"
}
顺便说一下,您发布的回复有差异。
如果想快速上网查询demo
我对编码还很陌生,在尝试将 JDBC 查询的结果与 XML 响应的结果进行比较时遇到了一些麻烦。
我使用的是 groovy 而不是 SoapUI 中内置的 XPATH,因为根据我请求中传递的参数,返回的节点数量可能会有所不同,我需要验证所有这些节点。
我使用我发现的各种示例构建了下面的脚本,因为我找不到一个可以执行我想要的操作的示例。我将 class 标记中的所有内容插入到 Eclipse 中,但它没有检测到任何语法错误。但是,当我 运行 SoapUI 中的脚本到达解析 xml 响应的部分时,没有构建任何内容。那么我的验证和断言当然会失败。 JDBC 数据构建得很好。
在此先感谢您的帮助。
import com.eviware.soapui.support.XmlHolder
import groovy.xml.XmlUtil
import groovy.util.XmlSlurper
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context)
class Model {
def campaignSysKey
def campaignName
def startDate
def endDate
def campaignCode
def buildJdbcData(row) {
row.with {
campaignSysKey = UPGRADETYPE
campaignName = SOURCEDESC
startDate = STARTDATE
endDate = ENDDATE
campaignCode = SOURCECODE
}
}
def buildXMLData(tagInfo) {
campaignSysKey = tagInfo.@campaignSysKey
campaignName = tagInfo.@campaignName
startDate = tagInfo.@startDate
endDate = tagInfo.@endDate
campaignCode = tagInfo.@campaignCode
}
}
def jdbcResponse = context.expand('${Validation#ResponseAsXml}')
def xmlResponse = context.expand('${OfferHistoryRequest#Response}')
def results = new XmlSlurper().parseText(jdbcResponse)
def jdbcDataObjects = []
results.ResultSet.Row.each { row ->
jdbcDataObjects.add(new Model().buildJdbcData(row))
}
def arrayOfTagInfo = new XmlSlurper().parseText(xmlResponse)
def xmlDataObjects = []
arrayOfTagInfo.TagInfo.each { tagInfo ->
xmlDataObjects.add(new Model().buildXMLData(tagInfo))
}
log.info "${jdbcDataObjects.size()}"
log.info "${xmlDataObjects.size()}"
if (jdbcDataObjects.size() != xmlDataObjects.size()) {
log.info("Jdbc resultset size is : ${jdbcDataObjects.size()} and XML result size is : ${xmlDataObjects.size()}")
}
assert jdbcDataObjects == xmlDataObjects, "Comparison of JDBC and XML data is failed"
JDBC 响应结构:
<Results>
<ResultSet fetchSize="0">
<Row rowNumber="1">
<UPGRADETYPE>1</UPGRADETYPE>
<SOURCEDESC>Desc 1</SOURCEDESC>
<STARTDATE>2015-01-01</STARTDATE>
<ENDDATE>2017-12-31</ENDDATE>
<SOURCECODE>ABC123</SOURCECODE>
</Row>
<Row rowNumber="2">
<UPGRADETYPE>2</UPGRADETYPE>
<SOURCEDESC>Desc 2</SOURCEDESC>
<STARTDATE>2015-01-01</STARTDATE>
<ENDDATE>2017-12-31</ENDDATE>
<SOURCECODE>XYZ987</SOURCECODE>
</Row>
</ResultSet>
</Results>
XML 响应(有意删除了 Holding 标签之间的数据,但保留它们以显示响应结构。我只关心 Campaign 节点):
<soap:Envelope xmlns:soap="http://sample.org">
<soap:Body>
<TXLife xmlns="http://sample.org">
<TXLifeResponse>
<TransRefGUID>123456</TransRefGUID>
<TransType tc="999"/>
<TransSubType tc="9909"/>
<BusinessService DataRep="VIEW"/>
<TransExeDate>2017-01-19-05:00</TransExeDate>
<TransExeTime>09:19:30.668-05:00</TransExeTime>
<StartRecord>1</StartRecord>
<TransResult>
<ResultCode tc="1"/>
<RecordsFound>2</RecordsFound>
</TransResult>
<OLifE>
<Holding id="Holding_B1234567">
</Holding>
<Campaign id="Campaign_B1234567_1" AppliesToCoverageID="Coverage_B1234567_1">
<CampaignSysKey>1</CampaignSysKey>
<CampaignName>Desc 1</CampaignName>
<StartDate>2015-01-01</StartDate>
<EndDate>2017-12-31</EndDate>
<CampaignCode>ABC123</CampaignCode>
</Campaign>
<Campaign id="Campaign_B1234567_2" AppliesToCoverageID="Coverage_B1234567_2">
<CampaignSysKey>2</CampaignSysKey>
<CampaignName>Desc 2</CampaignName>
<StartDate>2015-01-01</StartDate>
<EndDate>2017-12-31</EndDate>
<CampaignCode>XYZ987</CampaignCode>
</Campaign>
</OLifE>
</TXLifeResponse>
</TXLife>
</soap:Body>
</soap:Envelope>
来自 SoapUI 日志的错误:
Thu Jan 19 10:00:31 EST 2017:ERROR:java.lang.AssertionError: Comparison of JDBC and XML data is failed. Expression: (jdbcDataObjects == xmlDataObjects). Values: jdbcDataObjects = [X34143, X33582], xmlDataObjects = []
java.lang.AssertionError: Comparison of JDBC and XML data is failed. Expression: (jdbcDataObjects == xmlDataObjects). Values: jdbcDataObjects = [X34143, X33582], xmlDataObjects = []
at org.codehaus.groovy.runtime.InvokerHelper.assertFailed(InvokerHelper.java:404)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.assertFailed(ScriptBytecodeAdapter.java:650)
at Script5.run(Script5.groovy:67)
at com.eviware.soapui.support.scripting.groovy.SoapUIGroovyScriptEngine.run(SoapUIGroovyScriptEngine.java:92)
at com.eviware.soapui.support.scripting.groovy.SoapUIProGroovyScriptEngineFactory$SoapUIProGroovyScriptEngine.run(SoapUIProGroovyScriptEngineFactory.java:79)
at com.eviware.soapui.impl.wsdl.teststeps.WsdlGroovyScriptTestStep.run(WsdlGroovyScriptTestStep.java:156)
at com.eviware.soapui.impl.wsdl.panels.teststeps.GroovyScriptStepDesktopPanel$RunAction.run(GroovyScriptStepDesktopPanel.java:274)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
这是我修改过的脚本。
您制作并解决的脚本中的问题如下 -
- xml 元素读取不正确
- 使方法静态化
- 规范注释添加到 class 以便它可以进行比较
Groovy 脚本
//Class to model the different sources of data and create object
//so that those are comparable
@groovy.transform.Canonical
class Model {
String campaignSysKey
String campaignName
String startDate
String endDate
String campaignCode
static def buildJdbcData(row) {
def obj = new Model()
row.with {
obj.campaignSysKey = UPGRADETYPE
obj.campaignName = SOURCEDESC
obj.startDate = STARTDATE
obj.endDate = ENDDATE
obj.campaignCode = SOURCECODE
}
obj
}
static def buildXMLData(cmpgn) {
def obj = new Model()
obj.campaignSysKey = cmpgn.CampaignSysKey as String
obj.campaignName = cmpgn.CampaignName as String
obj.startDate = cmpgn.StartDate as String
obj.endDate = cmpgn.EndDate as String
obj.campaignCode = cmpgn.CampaignCode as String
obj
}
}
//Read the jdbc response from its step
def jdbcResponse = context.expand('${Validation#ResponseAsXml}')
//Read the xml response from its step
def xmlResponse = context.expand('${OfferHistoryRequest#Response}')
//Read & Create objects for jdbc response
def results = new XmlSlurper().parseText(jdbcResponse)
def jdbcDataObjects = []
results.ResultSet.Row.each { row ->
jdbcDataObjects.add(Model.buildJdbcData(row))
}
//Read & Create objects for xml response
def parsedXml = new XmlSlurper().parseText(xmlResponse)
def campaigns = parsedXml.'**'.findAll{it.name() == 'Campaign'}
def xmlDataObjects = []
campaigns.each { cmpgn ->
xmlDataObjects.add(Model.buildXMLData(cmpgn))
}
//Log both responses
log.info "Jdbc response records: ${jdbcDataObjects.size()}"
log.info "Xml response records: ${xmlDataObjects.size()}"
if (jdbcDataObjects.size() != xmlDataObjects.size()) {
log.info("Jdbc resultset size is : ${jdbcDataObjects.size()} and XML result size is : ${xmlDataObjects.size()}")
}
//Check if both object sizes are equal before comparing one to one
assert jdbcDataObjects.size() == xmlDataObjects.size(), "Both responses have not matched element count"
//Log both the objects
log.info jdbcDataObjects.toString()
log.info xmlDataObjects.toString()
//Compare now both the responses and show the difference
if (jdbcDataObjects != xmlDataObjects){
log.info "Both responses do not match"
for(int index=0;index<jdbcDataObjects.size();index++){
assert jdbcDataObjects[index] == xmlDataObjects[index], "Responses @ ${index+1} position do not match"
}
} else {
log.info "Both responses matches"
}
顺便说一下,您发布的回复有差异。
如果想快速上网查询demo