SoapUI+Groovy做接口自动化测试

摘要: 从头开始手把手教你新建一个SoapUI Project.

重点看是如何操作Excel中的Properties,以及错误Result Report。

关键词:SoapUI接口测试,接口自动化测试,数据驱动测试,SoapUI进阶使用, Groovy in SoapUI, SoapUI中Groovy的使用,数据分离。

阅读这篇文章需要一定的SoapUI基础,至少入过门,另外还需要一些Groovy的知识,当然如果你会java 也可以,这里用到的Groovy知识和Java很类似。

另外,本文的思路和我上一篇文章<零成本实现接口自动化测试 – Java+TestNG 测试Restful service>很相似,只不过把Java+TestNG的组合换成了SoapUI+Groovy, 另外测试对象也换成了基于Soap的web service, 依旧用Excel来管理数据,做到数据分离。

由于我用到的SoapUI是免费版本,相比Pro版,少很多的功能,像DataLoop之类的,所以只能通过Groovy写一些脚本来做数据驱动的测试。

1. 首先打开SoapUI, 新建一个Workspace 名为Demo

SoapUI+Groovy做接口自动化测试_第1张图片

2. 然后点击File->New soapUI Project

SoapUI+Groovy做接口自动化测试_第2张图片

3. 然后输入你的Project Name, WSDL 地址 点击OK

SoapUI+Groovy做接口自动化测试_第3张图片

4.输入服务的用户名密码 点击OK

SoapUI+Groovy做接口自动化测试_第4张图片

5. 项目工程建好了

SoapUI+Groovy做接口自动化测试_第5张图片

6. 右击ServicePort 建立TestSuite

SoapUI+Groovy做接口自动化测试_第6张图片

以其中一个接口为例 来生成用例

SoapUI+Groovy做接口自动化测试_第7张图片

输入TestSuite name 然后确认工程结构如下

SoapUI+Groovy做接口自动化测试_第8张图片

7. 通过右击TestCase -> Add Step  增加 Groovy Script 和 Properties

SoapUI+Groovy做接口自动化测试_第9张图片

增加四个Groovy Script, 并且命名成 Start, Process, Check Response, End

增加5个 Properties, 并且命名成Input, Baseline, Output, Result, fieldResult

调整它们的顺序,最后形成下图的工程目录结构

SoapUI+Groovy做接口自动化测试_第10张图片

8. 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');

9. 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

        {

        for (b=0;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

        {

        for (b=0;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

        {

            ws.addCell(new jxl.write.Label(a,0,result[a][0]));

            for (b=start_row;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

        {

            ws.addCell(new jxl.write.Label(a,0,result[a][0]));

            for (b=start_row;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

        {

            ws.addCell(new jxl.write.Label(a,0,output[a][0]));

            x= 1;

            for (b=start_row;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

                  {

                            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

    {

      setProperties(input[i][0],'',inputSheetName)

    }

      cleanProperty(baselineSheet);

      readBaseline(workbook,baselineSheet);

    for (i=0;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)&&(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

    {

        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

        {

            setProperties(input[i][0],input[i][m],inputSheetName)

        }

        for (j=0;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

        {

            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');

10. 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

      {

              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

            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

{

        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');

        }

}

11. 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');

12.配置

双击DemoProject, 点击下方的Properties tab

然后 Add property

SoapUI+Groovy做接口自动化测试_第11张图片
SoapUI+Groovy做接口自动化测试_第12张图片

Add 如下图所示的5个Property

SoapUI+Groovy做接口自动化测试_第13张图片

双击项目工程列表里的'Demo TestCase'

点击Properties tab

Add Property 如图

SoapUI+Groovy做接口自动化测试_第14张图片

Value 填Excel 的路径

SoapUI+Groovy做接口自动化测试_第15张图片

Excel数据工作簿里的Input sheet 如图

SoapUI+Groovy做接口自动化测试_第16张图片

接下来需要把Input里的column name 与 Soap request里的input 字段映射起来

双击Test Steps 里的request

将xml文件里的?用参数来代替

SoapUI+Groovy做接口自动化测试_第17张图片

左下角的TestRequest Properties  要填上用户名 密码

SoapUI+Groovy做接口自动化测试_第18张图片

Baseline sheet里要把输出结果的字段名都定义好, 因为是根据字段名去response里取结果的

每条用例期望结果都写好,用作和实际结果对比

SoapUI+Groovy做接口自动化测试_第19张图片

另外Check Response里的脚本需要设置一下

假设你的response xml文件结构如下

SoapUI+Groovy做接口自动化测试_第20张图片

如果你需要检查Soap body标签下的内容, 则你需要配置一下Check Response的脚本

将xml namespace的路径配置一下

SoapUI+Groovy做接口自动化测试_第21张图片

右击Project  Save一下Project 

最后可以运行了 双击Demo TestSuite  点击Run

SoapUI+Groovy做接口自动化测试_第22张图片

注意:Groovy脚本也是用第三方的jxl.jar操作excel文件的,所以这个jar需要放到SoapUI安装目录的\lib下面,才能运行成功。

打开Workbook 数据工作簿查看结果

Output

SoapUI+Groovy做接口自动化测试_第23张图片

Result

SoapUI+Groovy做接口自动化测试_第24张图片

Comparison

SoapUI+Groovy做接口自动化测试_第25张图片

备注:

这篇文章的部分内容转自下面的博客:

http://www.cnblogs.com/wade-xu/p/4236295.html

你可能感兴趣的:(SoapUI+Groovy做接口自动化测试)