重點看是如何操做Excel中的Properties,以及錯誤Result Report。html
關鍵詞:SoapUI接口測試,接口自動化測試,數據驅動測試,SoapUI進階使用, Groovy in SoapUI, SoapUI中Groovy的使用,數據分離。java
閱讀這篇文章須要必定的SoapUI基礎,至少入過門,另外還須要一些Groovy的知識,固然若是你會java 也能夠,這裏用到的Groovy知識和Java很相似。node
另外,本文的思路和我上一篇文章<零成本實現接口自動化測試 – Java+TestNG 測試Restful service>很類似,只不過把Java+TestNG的組合換成了SoapUI+Groovy, 另外測試對象也換成了基於Soap的web service, 依舊用Excel來管理數據,作到數據分離。web
因爲我用到的SoapUI是免費版本,相比Pro版,少不少的功能,像DataLoop之類的,因此只能經過Groovy寫一些腳原本作數據驅動的測試。數組
首先打開SoapUI, 新建一個Workspace 名爲Demoapp
而後點擊File->New soapUI Projectoop
而後輸入你的Project Name, WSDL 地址 點擊OK測試
輸入服務的用戶名密碼 點擊OKui
項目工程建好了this
右擊ServicePort 創建TestSuite
以其中一個接口爲例 來生成用例
輸入TestSuite name 而後確認
工程結構以下
經過右擊TestCase -> Add Step 增長 Groovy Script 和 Properties
增長四個Groovy Script, 而且命名成 Start, Process, Check Response, End
增長5個 Properties, 而且命名成Input, Baseline, Output, Result, fieldResult
調整它們的順序,最後造成下圖的工程目錄結構
Start腳本主要建立log文件
/*Check the log file, create folder and file if necessary*/ import java.io.*; def cal = Calendar.instance; def sysdate = cal.getTime(); def Y = cal.get(Calendar.YEAR); def M = cal.get(Calendar.MONTH)+1; def D = cal.get(Calendar.DATE); if (D<10) D = "0"+D; if (M<10) M = "0"+M; date = Y+"-"+M+"-"+D; time=sysdate.toString().replaceAll(':','-') def testSuites=testRunner.testCase.getTestSuite(); def testcase = testRunner.testCase; def logFolder = new File(context.expand('${#Project#LogFolder}')); def responseLogName = (context.expand('${#Project#LogFolder}')+date+'\\'+testSuites.name+' - '+ testcase.name +' - ' + time+".log"); def responseDetailLogName = (context.expand('${#Project#LogFolder}')+date+'\\'+testSuites.name+' - ' + testcase.name +' - ' + time + " Response Detail.log"); def responseLogFile = new File(responseLogName); def responseDetailLogFile = new File(responseDetailLogName); def subFolder= new File (context.expand('${#Project#LogFolder}')+date+'\\') /*Set date and Log Name to Project - Testcase Properties*/ testcase.setPropertyValue('date', date); testcase.setPropertyValue('LogFile - Check Response', responseLogName); testcase.setPropertyValue('LogFile - Response Detail', responseDetailLogName); if(!logFolder.exists()){ logFolder.mkdirs(); } if(!subFolder.exists()){ subFolder.mkdirs(); } /*Check the file, create a new one if not found*/ if(!responseLogFile.exists()){ responseLogFile.createNewFile(); } responseLogFile.append("---------------Test Start on "+sysdate+" ------------------------"+'\n'); if(!responseDetailLogFile.exists()){ responseDetailLogFile.createNewFile(); } responseDetailLogFile.append("---------------Test Start on "+sysdate+" ------------------------"+'\n');
Process腳本是整個工程的核心,讀取Excel數據文件的Input, Baseline 放入二維數組,而後循環讀入Input和Baseline這兩個Properties, 調用request, 取到Ouput和Result Properties的值放入Output, Result數組,最後更新Excel的Output, Result, Comparison sheet。
import java.io.*; import jxl.*; import java.text.DecimalFormat; def readInput(workbook,inputSheetName) { Sheet sheet=workbook.getSheet(inputSheetName); rows = sheet.getRows(); columns = sheet.getColumns(); /*Get content into array*/ input = new Object [columns][rows] for (a=0;a<columns;a++) { for (b=0;b<rows;b++) { input[a][b]= sheet.getCell(a,b).getContents(); } } } def readBaseline(workbook,sheetName) { Sheet sheet=workbook.getSheet(sheetName); Rows = sheet.getRows(); Columns = sheet.getColumns(); /*Get content into array*/ baseline = new Object [Columns][Rows] for (a=0;a<Columns;a++) { for (b=0;b<Rows;b++) { baseline[a][b]= sheet.getCell(a,b).getContents(); } } } def updateOutput(writableWorkbook,sheetName,start_row,rows,columnNo,result,resultTag){ Sheet[] sheet= writableWorkbook.getSheets(); ws = writableWorkbook.getSheet(sheetName); if(ws==null){ ws = writableWorkbook.createSheet(sheetName,sheet.length) } for (a=0;a<columnNo;a++) { ws.addCell(new jxl.write.Label(a,0,result[a][0])); for (b=start_row;b<rows;b++) { wc = new jxl.write.WritableCellFormat(); if (resultTag[a][b]=='PASS') { wc.setBackground(jxl.format.Colour.WHITE); ws.addCell(new jxl.write.Label(a,b,result[a][b],wc)); } else if(resultTag[a][b]=='FAIL'){ wc.setBackground(jxl.format.Colour.RED); ws.addCell(new jxl.write.Label(a,b,result[a][b],wc)); } } } } def updateResult(writableWorkbook,sheetName,start_row,rows,columnNo,result){ Sheet[] sheet= writableWorkbook.getSheets(); ws = writableWorkbook.getSheet(sheetName); if(ws==null){ ws = writableWorkbook.createSheet(sheetName,sheet.length) } for (a=0;a<columnNo;a++) { ws.addCell(new jxl.write.Label(a,0,result[a][0])); for (b=start_row;b<rows;b++) { wcf = new jxl.write.WritableCellFormat(); wcf.setBackground(jxl.format.Colour.RED); if(result[a][b] == 'FAIL'){ ws.addCell(new jxl.write.Label(a,b,result[a][b],wcf)); } else ws.addCell(new jxl.write.Label(a,b,result[a][b])); } } wc = new jxl.write.WritableCellFormat(); wcc = new jxl.write.WritableCellFormat(); wc.setBackground(jxl.format.Colour.GRAY_25); wcc.setBackground(jxl.format.Colour.LIGHT_TURQUOISE); ws.addCell(new jxl.write.Label(0,rows-3,result[0][rows-3],wcc)); ws.addCell(new jxl.write.Label(0,rows-2,result[0][rows-2],wc)); ws.addCell(new jxl.write.Label(0,rows-1,result[0][rows-1],wc)); } def updateComparison(writableWorkbook,sheetName,start_row,rows,columnNo,output,outputTag,result,baseline){ Sheet[] sheet= writableWorkbook.getSheets(); ws = writableWorkbook.getSheet(sheetName); if(ws==null){ ws = writableWorkbook.createSheet(sheetName,sheet.length) } for (a=0;a<columnNo;a++) { ws.addCell(new jxl.write.Label(a,0,output[a][0])); x= 1; for (b=start_row;b<rows;b++) { if(result[1][b] == 'FAIL'){ wc = new jxl.write.WritableCellFormat(); if (outputTag[a][b]=='PASS') { wc.setBackground(jxl.format.Colour.WHITE); ws.addCell(new jxl.write.Label(a,x,output[a][b],wc)); } else { wc.setBackground(jxl.format.Colour.RED); ws.addCell(new jxl.write.Label(a,x,output[a][b],wc)); } wbc = new jxl.write.WritableCellFormat(); wbc.setBackground(jxl.format.Colour.ICE_BLUE); ws.addCell(new jxl.write.Label(a,x+1,baseline[a][b],wbc)); x+=2; } } } } def removeSheetByName(writableWorkbook, name){ Sheet[] sheet= writableWorkbook.getSheets(); ws = writableWorkbook.getSheet(name); if(ws != null){ for (i = 0; i < sheet.length; i++) { sheetName = writableWorkbook.getSheet(i).getName(); if (sheetName.equalsIgnoreCase(name)) { writableWorkbook.removeSheet(i); } } } } def setProperties(Name,Value,Place) { name = Name; target = testRunner.testCase.getTestStepByName(Place); target.setPropertyValue(name,Value); } def cleanProperty(PropertyListName) { PropertyList = testRunner.testCase.getTestStepByName(PropertyListName); size=PropertyList.getPropertyCount(); if (size!=0) { for (i=0;i<size;i++) { PropertyList.removeProperty(PropertyList.getPropertyAt(0).name); } } } def logFile = new File(context.expand('${#TestCase#LogFile - Check Response}')); def xlsName = context.expand('${#TestCase#Workbook}'); def project = testRunner.testCase.getTestSuite().getProject(); def testSuite = testRunner.testCase.getTestSuite(); def testcase = testRunner.testCase def requests = testcase.getTestStepsOfType( com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep.class ) def request = requests[0]; inputSheetName = "Input"; baselineSheet = "Baseline"; outputSheet = "Output"; resultSheet = "Result"; fieldResult = testcase.getTestStepByName('fieldResult'); ComparisonSheet = "Comparison"; Baseline = testcase.getTestStepByName(baselineSheet); baselineSize = Baseline.getPropertyCount(); Output = testcase.getTestStepByName(outputSheet); def cal = Calendar.instance; def sysdate = cal.getTime(); sleepTime=context.expand('${#Project#sleepTime}').toInteger() try{ Workbook workbook=Workbook.getWorkbook(new File(xlsName)); cleanProperty(inputSheetName); readInput(workbook,inputSheetName); for (i=0;i<columns;i++) { setProperties(input[i][0],'',inputSheetName) } cleanProperty(baselineSheet); readBaseline(workbook,baselineSheet); for (i=0;i<Columns;i++) { setProperties(baseline[i][0],'',baselineSheet) } workbook.close(); }catch(Exception e){ e.printStackTrace(); } /*-----------Set runSelect as 'true' in Project property to run selected test cases from startTag till endTag-------*/ def runSelected = context.expand('${#Project#runSelected}') start_Test=1; end_Test=rows-1; def passNumbers = 0; def decFormat = new DecimalFormat("##.00%"); if ('true'.equalsIgnoreCase(runSelected)) { startTag=context.expand('${#Project#startTag}').toInteger(); endTag=context.expand('${#Project#endTag}').toInteger(); if((0<startTag)&&(startTag<rows)&&(endTag>=startTag)&&(rows>endTag)){ start_Test=startTag; end_Test=endTag; } } result = new Object [2][rows+3] result[0][0]='Case Description'; result[1][0]='Result' result[0][rows+1]='Start Time:'; result[1][rows+1]=sysdate.toString(); /*--New object and put the output name and value into this list--*/ output = new Object [baselineSize][rows] outputTag = new Object [baselineSize][rows] for (i=0;i<baselineSize;i++) { output[i][0]= Baseline.getPropertyAt(i).name; outputTag[i][0]= 'PASS'; } for (m=start_Test;m<=end_Test;m++) { logFile.append('\n'+ testcase.name + ": "+m+" "+ ". "+sysdate+'\n'); for (i=0;i<columns;i++) { setProperties(input[i][0],input[i][m],inputSheetName) } for (j=0;j<Columns;j++) { setProperties(baseline[j][0],baseline[j][m],baselineSheet) } testRunner.runTestStepByName(request.name); Thread.sleep(sleepTime); testRunner.runTestStepByName("Check Response"); result[0][m]=context.expand('${'+inputSheetName+'#Case Description}') result[1][m]=context.expand('${'+resultSheet+'#result}') if(result[1][m] == 'PASS'){ passNumbers++; } for (i=0;i<baselineSize;i++) { output[i][m]= Output.getPropertyAt(i).value; outputTag[i][m]= fieldResult.getPropertyAt(i).value; } } result[0][rows+2]='End Time:'; result[1][rows+2]=sysdate.toString(); result[0][rows]='Pass Percentage:'; passPercentage = decFormat.format(passNumbers/(end_Test-start_Test+1)); result[1][rows] = passPercentage /*--------------Update Output, Result, Comparison sheet---------*/ try{ workbook = Workbook.getWorkbook(new File(xlsName)); writableWorkbook = Workbook.createWorkbook(new File(xlsName), workbook); updateOutput(writableWorkbook,outputSheet,start_Test,end_Test+1,baselineSize,output,outputTag); updateResult(writableWorkbook,resultSheet,start_Test,rows+3,2,result); removeSheetByName(writableWorkbook,ComparisonSheet); if(passPercentage != '100.00%'){ updateComparison(writableWorkbook,ComparisonSheet,start_Test,end_Test+1,baselineSize,output,outputTag,result,baseline); } writableWorkbook.write(); writableWorkbook.close(); workbook.close(); }catch(Exception e){ e.printStackTrace(); } setProperties('passPercentage', passPercentage ,'Result'); testRunner.gotoStepByName('End');
Check Response 顧名思義,用來檢查返回結果, 經過XmlHolder getNodeValue 來取response各節點的值,而且填入Output Properties已做對比之用。
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); def requests = testcase.getTestStepsOfType( com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep.class ) def request = requests[0]; def response = request.testRequest.response; respXmlHolder = new XmlHolder(response.contentAsXml) //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); } def getspecifiedValue(field){ prefix = "//ns1:"; nodePath = "${prefix}${field}" specifiedValue = respXmlHolder.getNodeValue("${nodePath}") } testRunner.testCase.getTestStepByName(outputSheet).clearPropertyValues(); //normal output, status = '200 OK' if(statusCode.contains('200 OK')){ for (i=1;i<baselineSize;i++) { specifiedName = Baseline.getPropertyAt(i).name; specifiedValue = getspecifiedValue(specifiedName); if(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<baselineSize; t++){ setProperties(Baseline.getPropertyAt(t).name, '' ,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;i<baselineSize;i++) { if (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'); } }
End腳本 在log上打時間戳
def cal = Calendar.instance; def sysdate = cal.getTime(); responseLogFile = new File(context.expand('${#TestCase#LogFile - Check Response}')); responseDetailLogFile= new File(context.expand('${#TestCase#LogFile - Response Detail}')); responseLogFile.append('\n'+ "---------------Test End on " + sysdate.toString() + " ------------------------"+'\n'); responseDetailLogFile.append('\n'+ "---------------Test End on " + sysdate.toString() + " ------------------------"+'\n');
配置
雙擊DemoProject, 點擊下方的Properties tab
而後 Add property
Add 以下圖所示的5個Property
雙擊項目工程列表裏的'Demo TestCase'
點擊Properties tab
Add Property 如圖
Value 填Excel 的路徑
Excel數據工做簿裏的Input sheet 如圖
接下來須要把Input裏的column name 與 Soap request裏的input 字段映射起來
雙擊Test Steps 裏的request
將xml文件裏的?用參數來代替
左下角的TestRequest Properties 要填上用戶名 密碼
Baseline sheet裏要把輸出結果的字段名都定義好, 由於是根據字段名去response裏取結果的
每條用例指望結果都寫好,用做和實際結果對比
另外Check Response裏的腳本須要設置一下
假設你的response xml文件結構以下
若是你須要檢查Soap body標籤下的內容, 則你須要配置一下Check Response的腳本
將xml namespace的路徑配置一下
右擊Project Save一下Project
最後能夠運行了 雙擊Demo TestSuite 點擊Run
注意:Groovy腳本也是用第三方的jxl.jar操做excel文件的,因此這個jar須要放到SoapUI安裝目錄的\lib下面,才能運行成功。
打開Workbook 數據工做簿查看結果
Output
Result
Comparison
備註:
這篇文章的部份內容轉自下面的博客: