本文建立在手把手教你接口自动化测试 – SoapUI & Groovy的基础上。
亲测,只要严格按照上面那篇文章一点点配置下来,就一定能跑通的。可以来这里随便找几个接口试试。
脚本部分,Start、Process、End都没什么好改的,主要是获得返回值的时候破事多,所以本文主要说明Check Response脚本可以怎么改。
(请允许我加点注释)
import java.lang.*;
import java.util.*;
import groovy.lang.*;
import groovy.util.*;
import com.eviware.soapui.support.XmlHolder
baselineSheet = "Baseline";
outputSheet = "Output";
resultSheet = "Result";
def testcase = testRunner.testCase;
Baseline = testcase.getTestStepByName(baselineSheet)
baselineSize = Baseline.getPropertyCount();
Output = testcase.getTestStepByName(outputSheet);
//获得Test Step中的所有接口Request(SOAP类型的)
def requests = testcase.getTestStepsOfType( com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep.class )
//Test Step中的第一个接口Request
def request = requests[0];
def response = request.testRequest.response;
//这里就获取到返回值了
respXmlHolder = new XmlHolder(response.contentAsXml)
//返回xml如果有命名空间需要带上这个,ns1和后面的啥啥都根据实际情况修改。
//当然,我的接口没那么复杂,实际用的时候我是把这句注释掉的,所以无法进一步说明这个要怎么设置。
//declare namespace in xml response
respXmlHolder.declareNamespace("ns1", "http://schemas.xxx.com/v201203/yourservice")
def statusCode = request.testRequest.response.responseHeaders["#status#"].toString();
def setProperties(Name,Value,Place){
name = Name;
target = testRunner.testCase.getTestStepByName(Place);
target.setPropertyValue(name,Value);
}
//目测是通过xpath的形式取到返回的xml的标签内容
def getspecifiedValue(field){
prefix = "//ns1:";
nodePath = "${prefix}${field}"
specifiedValue = respXmlHolder.getNodeValue("${nodePath}")
}
testRunner.testCase.getTestStepByName(outputSheet).clearPropertyValues();
//normal output, status = '200 OK'
//在这里把结果写到output里
if(statusCode.contains('200 OK')){
//从baseline中读参数名称,用参数名称和命名空间拼出xpath,找到xml标签内容
//所以,这个方式适用范围有限,只能处理简单的、只有一级标签的、还不能有重名输出参数的xml。
for (i=1;iif(specifiedValue != null){
setProperties(specifiedName,specifiedValue,outputSheet)
} else {
setProperties(specifiedName,'',outputSheet)
}
}
} else
{
setProperties(Baseline.getPropertyAt(0).name,Baseline.getPropertyAt(0).value,outputSheet);
setProperties(Baseline.getPropertyAt(1).name,statusCode,outputSheet);
for(t=2; t'' ,outputSheet);
}
}
setProperties(Baseline.getPropertyAt(0).name,Baseline.getPropertyAt(0).value,outputSheet);
setProperties('result','PASS', resultSheet);
logFile = new File(context.expand('${#TestCase#LogFile - Check Response}'));
responseDetailLogFile= new File(context.expand('${#TestCase#LogFile - Response Detail}'));
logFile.append(" ------ Start Response Check "+ " @ "+Calendar.instance.getTime()+"\n");
responseDetailLogFile.append("\n"+ testcase.name + " -- " + Baseline.getPropertyAt(0).value+ "\n" + response+"\n");
/*--------Compare the result with Baseline and update the result accordingly---------*/
for (i=0;iif (Baseline.getPropertyAt(i).value==Output.getPropertyAt(i).value)
{
setProperties(Baseline.getPropertyAt(i).name,'PASS','fieldResult');
}
else
{
setProperties(Baseline.getPropertyAt(i).name,'FAIL','fieldResult');
setProperties('result','FAIL','Result');
}
}
soap类型
def requests = testcase.getTestStepsOfType( com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep.class )
rest类型
def requests = testcase.getTestStepsOfType( com.eviware.soapui.impl.wsdl.teststeps.RestTestRequestStep.class )
其实就是调用的class不同()其他都保持不变。
原文用的是xpath,但是我实际测接口时,遇到的大多是这种情况:
所以我得先把return的内容取出来,再把这个内容当成xml,再解析一次。
对了,这个方法里完全不会用到baseline里的参数名称,是用遍历的方式把所有的标签和内容都提出来。
//主要修改以下两个地方
//提取return标签,内容存入specifiedValue,再慢慢解析内容!!!
def getspecifiedValue(field){
prefix = "//return";//这里被我写死了
// nodePath = "${prefix}${field}" 这个就不要了
specifiedValue = respXmlHolder.getNodeValue("${prefix}") //specifiesValue里就是return里的内容
}
testRunner.testCase.getTestStepByName(outputSheet).clearPropertyValues();
//normal output, status = '200 OK'
//结果写入output在这里
if(statusCode.contains('200 OK')){
specifiedValue = getspecifiedValue("specifiedName");
// new XmlParser().parseText(specifiedValue.toString());把字符串形式的xml内容,转成xml格式
returnXml= new XmlParser().parseText(specifiedValue.toString());
returnXml.value().each{
log.info(it.name());//log.info可在soapui的log output里打印日志,调试时很方便
setProperties(it.name(),it.text(),outputSheet)
}
} else {
setProperties(Baseline.getPropertyAt(0).name,Baseline.getPropertyAt(0).value,outputSheet);
}
解释一下returnXml.value()。
返回的xml中,return标签的内容为
<return>1 -2 ]]>return>
specifiedValue.toString()的内容为return中的内容。即
1 -2 ]]>
这个内容xml格式化之后就是returnXml,打印returnXml.value()的内容可知,为
[handleResult[attributes={}; value=[1]], errMessage[attributes={}; value=[-2]]]
这是一个数组啊!!!所以,当成一个数组来遍历就可以了。
it.name()是handleResult,it.text()是handleResult里的value。其他参数同理。
处理Json需要在脚本里import groovy.json.JsonSlurper
if(statusCode.contains('200 OK')){
specifiedValue = request.testRequest.response.responseContent.toString();
returnJson= new JsonSlurper().parseText(specifiedValue);
for(i = 0;i<returnJson.size();i++){
def key = returnJson.keySet().getAt(i);
def value = returnJson.values().getAt(i).toString();
setProperties(key,value,outputSheet);
}
}else{
setProperties(Baseline.getPropertyAt(0).name,Baseline.getPropertyAt(0).value,outputSheet);
}
并没有用到getspecifiedValue方法,也没有用到respXmlHolder参数。
直接将返回值的内容以字符串形式赋给specifiedValue
使用JsonSlurper创建json对象,然后按照java里处理json的方式遍历就行。
keySet()获取keyset…………values()获取values,都是集合,然后用getAt(index)得到具体的值。
因为value有可能也是个list之类的东西,所以我这里做了个toString()。
而且这个例子仅针对普通的只有一级的非数组的json。比如
{
result:1,
errMessage:-2
}
这种形式。
如果json比较复杂的话,就多遍历几次就好。
2、还有种返回类型忘记说了,就直接返回字符串的。
request.testRequest.response.responseContent.toString();
这样就可以了。
3、获取接口的属性值
def requests = testcase.getTestStepsOfType( com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep.class )
def request = requests[0];
选中接口时可以在左下角看到这些属性,像上面那样得到接口request后,可以得到这里面的部分信息。
def requestAdress = request.getPropertyValue('Endpoint');
可获得Endpoint的Value,以此类推。
Custom Properties里的内容大部分都能用这种方法获取到,有些需要用其他方法。
比如在testRequest里要得到接口名称,接口名称在Operation里。
就需要使用request.operation.name 来得到pushSimiAnalyResult这个Value。
总之我认为这些属性都是能通过某种手段得到的,实际用时一点点去猜去试去log.info总能找到方法……
上面两个是soap类型的,下面是获得rest类型的接口地址的方法
def requestAdress = request.service+request.resource.toString().substring(request.resource.toString().indexOf("/"));
总之就是不折手段拼出来即可。
4、输出到txt
logFile = new File(context.expand(‘${#TestCase#LogFile - Check Response}’));
logFile.append(“要打印到txt的内容!”);
这个LogFile,emmmmmm,反正不改其他地方的话,可以使用logFile.append把一些自定义的信息一起打印到txt里,为什么会生成一个txt文件我也说不清楚。
5、正则表达式
requestAdress.substring(requestAdress.lastIndexOf("/")+1) ==~ /[a-z0-9A-Z]{4,40}/
==~就是求正则表达式的方法,右边是正则表达式,写法为前后用/:/里面使用正常的正则表达式写法/
匹配返回true,否则false。