[SoapUI] 比较两个不同环境下的XML Response, 从外部文件读取允许的偏差值,输出结果到文本文件
1. 获取TP和Live的xml response
2. 以其中一个数据点 ticker 为基准进行比较,ticker相同才进行比对
3. 从外部文件读取各个数据点允许的偏差值,偏差范围以内的不同认为是正常
4. API中的数据点提供的是Data ID, 而用户希望错误日志以UI上的Data Name进行打印,因此需要从外部文件读取Data ID和Data Name的映射关系
5. 计算Data point失败的比例
6. 将错误日志输出到本地的文本文件
import static java.lang.Math.*
import com.eviware.soapui.support.GroovyUtils
import com.eviware.soapui.support.XmlHolder
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
// The parameter allowableDeviation means the allowable deviation can be ? percent, e.g. allowableDeviation = 0.03 , the allowable deviation is 3%
def allowableDeviation
// Fail message
ArrayList failMessageList = new ArrayList()
String failMessage
// Get test steps
def currentStepIndex = context.currentStepIndex
String currentStepName = testRunner.testCase.getTestStepAt(currentStepIndex).name
String previousStepName = testRunner.testCase.getTestStepAt(currentStepIndex-1).name
String prePreStepName = testRunner.testCase.getTestStepAt(currentStepIndex-2).name
// File path
String testDataPath = testRunner.testCase.testSuite.project.getPropertyValue( "testDataPath" )
String dataIdMappingFile = testDataPath+"\\DataIdMappingPA.xml"
String dataDeviationFile = testDataPath+"\\RTQDataAllowableDeviation.xlsx"
String testResultPath = testRunner.testCase.testSuite.project.getPropertyValue( "testResultPath" )
// Get allowable deviation
HashMap dataDeviationMap = getAllowableDeviation(dataDeviationFile)
// Get response
def groovyUtils = new GroovyUtils( context )
def xmlHolderLive = groovyUtils.getXmlHolder( prePreStepName+"#ResponseAsXml" )
def xmlHolderTP = groovyUtils.getXmlHolder( previousStepName+"#ResponseAsXml" )
// Get records
def nodesArrayLive = xmlHolderLive.getDomNodes("//B/I" )
def nodesArrayTP =xmlHolderTP.getDomNodes("//B/I")
List nodesListLive = nodesArrayLive.toList()
List nodesListTP = nodesArrayTP.toList()
int recordsNumberLive = nodesListLive.size()
int recordsNumberTP = nodesListTP.size()
log.info "Total Records Number on Live = "+recordsNumberLive
log.info "Total Records Number on TP = "+recordsNumberTP
// Failed records
int failedRecordsNumber=0
// Get Map of Data ID and Data Name
getMapOfDataIdAndNameFromExternelFile(dataIdMappingFile)
HashMap dataIDAndNameMap = new HashMap()
dataIDAndNameMap = getMapOfDataIdAndNameFromExternelFile(dataIdMappingFile)
def attributesNumber = nodesListLive.get(0).attributes.getLength()
// Get Map of Data Name and Data Value
HashMap recordMapLive = new HashMap()
HashMap recordMapTP = new HashMap()
def dataName
def dataValue
recordMapLive = getRecordMap(nodesListLive,recordsNumberLive,attributesNumber,dataIDAndNameMap,recordMapLive)
recordMapTP = getRecordMap(nodesListTP,recordsNumberTP,attributesNumber,dataIDAndNameMap,recordMapTP)
// Compare data value on TP and Live based on ticker
Iterator iter = recordMapLive.entrySet().iterator()
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next()
def ticker = entry.getKey()
HashMap dataMapLive = entry.getValue()
HashMap dataMapTP =recordMapTP.get(ticker)
Iterator iter2 = dataMapLive.entrySet().iterator()
while (iter2.hasNext()) {
Map.Entry entry2 = (Map.Entry) iter2.next()
def dataNameLive = entry2.getKey()
def dataValueLive = entry2.getValue()
def dataValueTP = dataMapTP.get(dataNameLive)
if(dataValueTP==null){
failMessage = "Ticker = "+ticker+" , Data Point = "+dataNameLive+" , TP = "+"Not Exist"+" , Live = "+dataValueLive
failMessageList.add(failMessage)
}
if(dataValueLive != dataValueTP){
if(((dataValueTP=="")&&(dataValueTP!=""))||((dataValueTP!="")&&(dataValueTP==""))){
failMessage = "Ticker = "+ticker+" , Data Point = "+dataNameLive+" , TP = "+dataValueTP+" , Live = "+dataValueLive
failMessageList.add(failMessage)
}
if(dataValueLive.isFloat()&&dataValueTP.isFloat()){
allowableDeviation = dataDeviationMap.get(dataNameLive)
if(allowableDeviation==null){
allowableDeviation=0
}
addFailMessageAboutFloatDiff(failMessageList,ticker,dataNameLive,dataValueTP,dataValueLive, allowableDeviation)
}
else{
failMessage = "Ticker = "+ticker+" , Data Point = "+dataNameLive+" , TP = "+dataValueTP+" , Live = "+dataValueLive
failMessageList.add(failMessage)
}
}
}
}
// Get total data points number
int totalDataPointsNumber = recordsNumberLive*attributesNumber
log.info "Total Data Points Number = "+totalDataPointsNumber
// Get failed data points number
int failedDataPointsNumber = failMessageList.size()
log.info "Failed Data Points Number = "+failedDataPointsNumber
def failedPercentage = failedDataPointsNumber/totalDataPointsNumber
log.error "Failed Data Points Percentage = "+((int)(failedPercentage*10000))/100+"%"
// Print out all failed data points
if(failedDataPointsNumber>0){
def testResultFile = new File(testResultPath+ currentStepName+".txt")
if (testResultFile.exists()) {
testResultFile.delete()
}
for(j=0; j<failedDataPointsNumber; j++){
String currentFailMessage = failMessageList.get(j)
log.error currentFailMessage
testResultFile.append(currentFailMessage+"\n" )
}
assert false,failMessageList.get(0)
}
// Get map of ticker and other data points list
def getRecordMap(List nodesList,int recordsNumber,int attributesNumber,HashMap dataIDAndNameMap,HashMap recordMap){
HashMap map = new HashMap()
for(int i=0;i<recordsNumber;i++){
attributes = nodesList.get(i).getAttributes()
ticker = attributes.item(3).value
if(ticker!=""){
HashMap dataMap = new HashMap()
for(int j=4;j<attributesNumber;j++){
dataID = attributes.item(j).name
dataName = dataIDAndNameMap.get(dataID)
dataValue = attributes.item(j).value
dataMap.put(dataName,dataValue)
}
map.put(ticker,dataMap)
}
}
return map
}
// Get map of Data ID and Data Name from externel file
def getMapOfDataIdAndNameFromExternelFile(String dataIdMappingFile){
HashMap map = new HashMap()
def xmlDataIdMapping= new XmlParser().parse(dataIdMappingFile)
for(it in xmlDataIdMapping.f){
String mapDataID = "${it.attribute("i")}"
String mapDataName = "${it.attribute("udlbl")}"
map.put(mapDataID, mapDataName)
}
return map
}
// Add fail message when two float data is different
def addFailMessageAboutFloatDiff(ArrayList failMessageList,String ticker,String dataName,String dataValueStringTP,String dataValueStringLive,def allowableDeviation){
Float dataValueTP = dataValueStringTP.toFloat()
Float dataValueLive = dataValueStringLive.toFloat()
if ((dataValueLive ==0)&&(dataValueTP == 0)){
return
}
Float benchmark = dataValueLive
if (dataValueLive ==0){
benchmark = dataValueTP
}
if(Math.abs((dataValueLive-dataValueTP )/benchmark)>allowableDeviation){
failMessage ="Ticker = "+ticker+" , Data Point = "+dataName+" , TP = "+dataValueTP+" , Live = "+dataValueLive+" , Allowable Deviation = "+allowableDeviation
failMessageList.add(failMessage)
}
}
// Get allowable deviation from externel file
def getAllowableDeviation(String dataDeviationFile){
HashMap map = new HashMap()
File file = new File(dataDeviationFile)
try{
XSSFWorkbook wb = new XSSFWorkbook(new FileInputStream(dataDeviationFile))
XSSFSheet sheet = wb.getSheetAt(0)
Row row
Cell cellDataName
Cell cellDataDeviation
int rows = sheet.physicalNumberOfRows
def dataName
def dataDeviation
(1..<rows).each{ r ->
row = sheet.getRow(r)
if (row != null){
cellDataName = row.getCell(1)
cellDataDeviation = row.getCell(2)
if (cellDataName != null){
dataName = cellDataName.getStringCellValue()
}
if (cellDataDeviation != null){
switch (cellDataDeviation.getCellType()){
case cellDataDeviation.CELL_TYPE_NUMERIC:
dataDeviation = cellDataDeviation.getNumericCellValue()
break
case cellDataDeviation.CELL_TYPE_STRING:
dataDeviation = cellDataDeviation.getStringCellValue()
break
case cellDataDeviation.CELL_TYPE_BLANK:
break
default:
break
}
}
}
map.put(dataName,dataDeviation)
}
return map
}
catch (Exception e){
log.info "Exception :" + e.getMessage()
}
}
浙公网安备 33010602011771号