zoukankan      html  css  js  c++  java
  • http接口自动化测试框架实现

    一、测试需求描述

    对服务后台一系列的http接口功能测试。

    输入:根据接口描述构造不同的参数输入值

    输出:XML文件

    eg:http://xxx.com/xxx_product/test/content_book_list.jsp?listid=1

     

    二、实现方法

    1、选用Python脚本来驱动测试

    2、采用Excel表格管理测试数据,包括用例的管理、测试数据录入、测试结果显示等等,这个需要封装一个Excel的类即可。

    3、调用http接口采用Python封装好的API即可

    4、测试需要的http组装字符转处理即可

    5、设置2个检查点,XML文件中的返回值字段(通过解析XML得到);XML文件的正确性(文件对比)

    6、首次执行测试采用半自动化的方式,即人工检查输出的XML文件是否正确,一旦正确将封存XML文件,为后续回归测试的预期结果,如果发现错误手工修正为预期文件。(注意不是每次测试都人工检查该文件,只首次测试的时候才检查)

     

    三、Excel表格样式

    Excel模板 

    四、实现代码(代码才是王道,有注释很容易就能看明白的)

    1、测试框架代码

    [python] view plain copy
    1. #****************************************************************  
    2. # TestFrame.py  
    3. # Author     : Vince  
    4. # Version    : 1.1.2  
    5. # Date       : 2011-3-14  
    6. # Description: 自动化测试平台  
    7. #****************************************************************  
    8.   
    9. import os,sys, urllib, httplib, profile, datetime, time  
    10. from xml2dict import XML2Dict  
    11. import win32com.client  
    12. from win32com.client import Dispatch  
    13. import xml.etree.ElementTree as et  
    14. #import MySQLdb  
    15.   
    16. #Excel表格中测试结果底色  
    17. OK_COLOR=0xffffff  
    18. NG_COLOR=0xff  
    19. #NT_COLOR=0xffff  
    20. NT_COLOR=0xC0C0C0  
    21.   
    22. #Excel表格中测试结果汇总显示位置  
    23. TESTTIME=[1, 14]  
    24. TESTRESULT=[2, 14]  
    25.   
    26. #Excel模版设置  
    27. #self.titleindex=3        #Excel中测试用例标题行索引  
    28. #self.casebegin =4        #Excel中测试用例开始行索引  
    29. #self.argbegin   =3       #Excel中参数开始列索引  
    30. #self.argcount  =8        #Excel中支持的参数个数  
    31. class create_excel:  
    32.     def __init__(self, sFile, dtitleindex=3, dcasebegin=4, dargbegin=3, dargcount=8):  
    33.         self.xlApp = win32com.client.Dispatch('et.Application')   #MS:Excel  WPS:et  
    34.         try:  
    35.             self.book = self.xlApp.Workbooks.Open(sFile)  
    36.         except:  
    37.             print_error_info()  
    38.             print "打开文件失败"  
    39.             exit()  
    40.         self.file=sFile  
    41.         self.titleindex=dtitleindex  
    42.         self.casebegin=dcasebegin  
    43.         self.argbegin=dargbegin  
    44.         self.argcount=dargcount  
    45.         self.allresult=[]  
    46.           
    47.         self.retCol=self.argbegin+self.argcount  
    48.         self.xmlCol=self.retCol+1  
    49.         self.resultCol=self.xmlCol+1  
    50.   
    51.     def close(self):  
    52.         #self.book.Close(SaveChanges=0)  
    53.         self.book.Save()  
    54.         self.book.Close()  
    55.         #self.xlApp.Quit()  
    56.         del self.xlApp  
    57.           
    58.     def read_data(self, iSheet, iRow, iCol):  
    59.         try:  
    60.             sht = self.book.Worksheets(iSheet)  
    61.             sValue=str(sht.Cells(iRow, iCol).Value)  
    62.         except:  
    63.             self.close()  
    64.             print('读取数据失败')  
    65.             exit()  
    66.         #去除'.0'  
    67.         if sValue[-2:]=='.0':  
    68.             sValue = sValue[0:-2]  
    69.         return sValue  
    70.   
    71.     def write_data(self, iSheet, iRow, iCol, sData, color=OK_COLOR):  
    72.         try:  
    73.             sht = self.book.Worksheets(iSheet)  
    74.             sht.Cells(iRow, iCol).Value = sData.decode("utf-8")  
    75.             sht.Cells(iRow, iCol).Interior.Color=color  
    76.             self.book.Save()  
    77.         except:  
    78.             self.close()  
    79.             print('写入数据失败')  
    80.             exit()  
    81.       
    82.     #获取用例个数      
    83.     def get_ncase(self, iSheet):  
    84.         try:  
    85.             return self.get_nrows(iSheet)-self.casebegin+1  
    86.         except:  
    87.             self.close()  
    88.             print('获取Case个数失败')  
    89.             exit()  
    90.       
    91.     def get_nrows(self, iSheet):  
    92.         try:  
    93.             sht = self.book.Worksheets(iSheet)  
    94.             return sht.UsedRange.Rows.Count  
    95.         except:  
    96.             self.close()  
    97.             print('获取nrows失败')  
    98.             exit()  
    99.   
    100.     def get_ncols(self, iSheet):  
    101.         try:  
    102.             sht = self.book.Worksheets(iSheet)  
    103.             return sht.UsedRange.Columns.Count  
    104.         except:  
    105.             self.close()  
    106.             print('获取ncols失败')  
    107.             exit()  
    108.       
    109.     def del_testrecord(self, suiteid):  
    110.         try:  
    111.             #为提升性能特别从For循环提取出来  
    112.             nrows=self.get_nrows(suiteid)+1  
    113.             ncols=self.get_ncols(suiteid)+1  
    114.             begincol=self.argbegin+self.argcount  
    115.               
    116.             #提升性能  
    117.             sht = self.book.Worksheets(suiteid)  
    118.   
    119.             for row in range(self.casebegin, nrows):  
    120.                 for col in range(begincol, ncols):  
    121.                     str=self.read_data(suiteid, row, col)  
    122.                     #清除实际结果[]  
    123.                     startpos = str.find('[')  
    124.                     if startpos>0:  
    125.                         str = str[0:startpos].strip()  
    126.                         self.write_data(suiteid, row, col, str, OK_COLOR)  
    127.                     else:  
    128.                         #提升性能  
    129.                         sht.Cells(row, col).Interior.Color = OK_COLOR  
    130.                 #清除TestResul列中的测试结果,设置为NT  
    131.                 self.write_data(suiteid, row,  self.argbegin+self.argcount+1, ' ', OK_COLOR)  
    132.                 self.write_data(suiteid, row, self.resultCol, 'NT', NT_COLOR)  
    133.         except:  
    134.             self.close()  
    135.             print('清除数据失败')  
    136.             exit()  
    137.   
    138. #执行调用  
    139. def HTTPInvoke(IPPort, url):  
    140.     conn = httplib.HTTPConnection(IPPort)  
    141.     conn.request("GET", url)  
    142.     rsps = conn.getresponse()  
    143.     data = rsps.read()  
    144.     conn.close()  
    145.     return data  
    146.   
    147. #获取用例基本信息[Interface,argcount,[ArgNameList]]  
    148. def get_caseinfo(Data, SuiteID):  
    149.     caseinfolist=[]  
    150.     sInterface=Data.read_data(SuiteID, 1, 2)   
    151.     argcount=int(Data.read_data(SuiteID, 2, 2))   
    152.       
    153.     #获取参数名存入ArgNameList   
    154.     ArgNameList=[]  
    155.     for i in range(0, argcount):  
    156.         ArgNameList.append(Data.read_data(SuiteID, Data.titleindex, Data.argbegin+i))    
    157.       
    158.     caseinfolist.append(sInterface)  
    159.     caseinfolist.append(argcount)  
    160.     caseinfolist.append(ArgNameList)  
    161.     return caseinfolist  
    162.   
    163. #获取输入  
    164. def get_input(Data, SuiteID, CaseID, caseinfolist):  
    165.     sArge=''  
    166.     #参数组合  
    167.     for j in range(0, caseinfolist[1]):  
    168.         if Data.read_data(SuiteID, Data.casebegin+CaseID, Data.argbegin+j) != "None":  
    169.             sArge=sArge+caseinfolist[2][j]+'='+Data.read_data(SuiteID, Data.casebegin+CaseID, Data.argbegin+j)+'&'   
    170.       
    171.     #去掉结尾的&字符  
    172.     if sArge[-1:]=='&':  
    173.         sArge = sArge[0:-1]     
    174.     sInput=caseinfolist[0]+sArge    #组合全部参数  
    175.     return sInput  
    176.    
    177. #结果判断   
    178. def assert_result(sReal, sExpect):  
    179.     sReal=str(sReal)  
    180.     sExpect=str(sExpect)  
    181.     if sReal==sExpect:  
    182.         return 'OK'  
    183.     else:  
    184.         return 'NG'  
    185.   
    186. #将测试结果写入文件  
    187. def write_result(Data, SuiteId, CaseId, resultcol, *result):  
    188.     if len(result)>1:  
    189.         ret='OK'  
    190.         for i in range(0, len(result)):  
    191.             if result[i]=='NG':  
    192.                 ret='NG'  
    193.                 break  
    194.         if ret=='NG':  
    195.             Data.write_data(SuiteId, Data.casebegin+CaseId, resultcol,ret, NG_COLOR)  
    196.         else:  
    197.             Data.write_data(SuiteId, Data.casebegin+CaseId, resultcol,ret, OK_COLOR)  
    198.         Data.allresult.append(ret)  
    199.     else:  
    200.         if result[0]=='NG':  
    201.             Data.write_data(SuiteId, Data.casebegin+CaseId, resultcol,result[0], NG_COLOR)  
    202.         elif result[0]=='OK':  
    203.             Data.write_data(SuiteId, Data.casebegin+CaseId, resultcol,result[0], OK_COLOR)  
    204.         else:  #NT  
    205.             Data.write_data(SuiteId, Data.casebegin+CaseId, resultcol,result[0], NT_COLOR)  
    206.         Data.allresult.append(result[0])  
    207.       
    208.     #将当前结果立即打印  
    209.     print 'case'+str(CaseId+1)+':', Data.allresult[-1]  
    210.   
    211. #打印测试结果  
    212. def statisticresult(excelobj):  
    213.     allresultlist=excelobj.allresult  
    214.     count=[0, 0, 0]  
    215.     for i in range(0, len(allresultlist)):  
    216.         #print 'case'+str(i+1)+':', allresultlist[i]  
    217.         count=countflag(allresultlist[i],count[0], count[1], count[2])  
    218.     print 'Statistic result as follow:'  
    219.     print 'OK:', count[0]  
    220.     print 'NG:', count[1]  
    221.     print 'NT:', count[2]  
    222.   
    223. #解析XmlString返回Dict  
    224. def get_xmlstring_dict(xml_string):  
    225.     xml = XML2Dict()  
    226.     return xml.fromstring(xml_string)  
    227.       
    228. #解析XmlFile返回Dict   
    229. def get_xmlfile_dict(xml_file):  
    230.     xml = XML2Dict()  
    231.     return xml.parse(xml_file)  
    232.   
    233. #去除历史数据expect[real]  
    234. def delcomment(excelobj, suiteid, iRow, iCol, str):  
    235.     startpos = str.find('[')  
    236.     if startpos>0:  
    237.         str = str[0:startpos].strip()  
    238.         excelobj.write_data(suiteid, iRow, iCol, str, OK_COLOR)  
    239.     return str  
    240.       
    241. #检查每个item (非结构体)  
    242. def check_item(excelobj, suiteid, caseid,real_dict, checklist, begincol):  
    243.     ret='OK'  
    244.     for checkid in range(0, len(checklist)):  
    245.         real=real_dict[checklist[checkid]]['value']  
    246.         expect=excelobj.read_data(suiteid, excelobj.casebegin+caseid, begincol+checkid)  
    247.           
    248.         #如果检查不一致测将实际结果写入expect字段,格式:expect[real]  
    249.         #将return NG  
    250.         result=assert_result(real, expect)  
    251.         if result=='NG':  
    252.             writestr=expect+'['+real+']'  
    253.             excelobj.write_data(suiteid, excelobj.casebegin+caseid, begincol+checkid, writestr, NG_COLOR)  
    254.             ret='NG'  
    255.     return ret  
    256.   
    257. #检查结构体类型  
    258. def check_struct_item(excelobj, suiteid, caseid,real_struct_dict, structlist, structbegin, structcount):  
    259.     ret='OK'  
    260.     if structcount>1:  #传入的是List  
    261.         for structid in range(0, structcount):  
    262.             structdict=real_struct_dict[structid]  
    263.             temp=check_item(excelobj, suiteid, caseid,structdict, structlist, structbegin+structid*len(structlist))  
    264.             if temp=='NG':  
    265.                 ret='NG'  
    266.                        
    267.     else#传入的是Dict  
    268.         temp=check_item(excelobj, suiteid, caseid,real_struct_dict, structlist, structbegin)  
    269.         if temp=='NG':  
    270.             ret='NG'  
    271.               
    272.     return ret  
    273.   
    274. #获取异常函数及行号  
    275. def print_error_info():  
    276.     """Return the frame object for the caller's stack frame."""  
    277.     try:  
    278.         raise Exception  
    279.     except:  
    280.         f = sys.exc_info()[2].tb_frame.f_back  
    281.     print (f.f_code.co_name, f.f_lineno)    
    282.   
    283. #测试结果计数器,类似Switch语句实现  
    284. def countflag(flag,ok, ng, nt):   
    285.     calculation  = {'OK':lambda:[ok+1, ng, nt],    
    286.                          'NG':lambda:[ok, ng+1, nt],                        
    287.                          'NT':lambda:[ok, ng, nt+1]}       
    288.     return calculation[flag]()   

    2、项目测试代码

    [python] view plain copy
    1. # -*- coding: utf-8 -*-  
    2. #****************************************************************  
    3. # xxx_server_case.py  
    4. # Author     : Vince  
    5. # Version    : 1.0  
    6. # Date       : 2011-3-10  
    7. # Description: 内容服务系统测试代码  
    8. #****************************************************************  
    9.   
    10. from testframe import *  
    11. from common_lib import *  
    12.   
    13. httpString='http://xxx.com/xxx_product/test/'  
    14. expectXmldir=os.getcwd()+'/TestDir/expect/'  
    15. realXmldir=os.getcwd()+'/TestDir/real/'  
    16.   
    17. def run(interface_name, suiteid):  
    18.     print '【'+interface_name+'】' + ' Test Begin,please waiting...'  
    19.     global expectXmldir, realXmldir  
    20.       
    21.     #根据接口名分别创建预期结果目录和实际结果目录  
    22.     expectDir=expectXmldir+interface_name  
    23.     realDir=realXmldir+interface_name  
    24.     if os.path.exists(expectDir) == 0:  
    25.         os.makedirs(expectDir)  
    26.     if os.path.exists(realDir) == 0:  
    27.         os.makedirs(realDir)  
    28.       
    29.     excelobj.del_testrecord(suiteid)  #清除历史测试数据  
    30.     casecount=excelobj.get_ncase(suiteid) #获取case个数  
    31.     caseinfolist=get_caseinfo(excelobj, suiteid) #获取Case基本信息  
    32.       
    33.     #遍历执行case  
    34.     for caseid in range(0, casecount):  
    35.         #检查是否执行该Case  
    36.         if excelobj.read_data(suiteid,excelobj.casebegin+caseid, 2)=='N':  
    37.             write_result(excelobj, suiteid, caseid, excelobj.resultCol, 'NT')  
    38.             continue #当前Case结束,继续执行下一个Case  
    39.           
    40.         #获取测试数据  
    41.         sInput=httpString+get_input(excelobj, suiteid, caseid, caseinfolist)     
    42.         XmlString=HTTPInvoke(com_ipport, sInput)     #执行调用  
    43.           
    44.         #获取返回码并比较  
    45.         result_code=et.fromstring(XmlString).find("result_code").text  
    46.         ret1=check_result(excelobj, suiteid, caseid,result_code, excelobj.retCol)  
    47.           
    48.         #保存预期结果文件  
    49.         expectPath=expectDir+'/'+str(caseid+1)+'.xml'  
    50.         #saveXmlfile(expectPath, XmlString)  
    51.           
    52.         #保存实际结果文件  
    53.         realPath=realDir+'/'+str(caseid+1)+'.xml'  
    54.         saveXmlfile(realPath, XmlString)  
    55.           
    56.         #比较预期结果和实际结果  
    57.         ret2= check_xmlfile(excelobj, suiteid, caseid,expectPath, realPath)  
    58.           
    59.         #写测试结果  
    60.         write_result(excelobj, suiteid, caseid, excelobj.resultCol, ret1, ret2)  
    61.     print '【'+interface_name+'】' + ' Test End!'  

    3、测试入口

    [python] view plain copy
    1. # -*- coding: utf-8 -*-  
    2. #****************************************************************  
    3. # main.py  
    4. # Author     : Vince  
    5. # Version    : 1.0  
    6. # Date       : 2011-3-16  
    7. # Description: 测试组装,用例执行入口  
    8. #****************************************************************  
    9.   
    10. from testframe import *  
    11. from xxx_server_case import *  
    12. import xxx_server_case  
    13.   
    14. #产品系统接口测试  
    15. #设置测试环境  
    16. xxx_server_case.excelobj=create_excel(os.getcwd()+'/TestDir/xxx_Testcase.xls')  
    17. xxx_server_case.com_ipport=xxx.com'  
    18.   
    19. #Add testsuite begin  
    20. run("xxx_book_list"4)  
    21. #Add other suite from here  
    22. #Add testsuite end  
    23.   
    24. statisticresult(xxx_server_case.excelobj)  
    25. xxx_server_case.excelobj.close()  
  • 相关阅读:
    [hdu-2048] 神、上帝以及老天爷
    or1200中IMMU分析(续)
    Java Applet读写client串口——终极篇
    树莓派_Linux串口编程_实现自发自收
    2014百度实习生面试题(部分)具体解释
    Leetcode
    eclipse+webservice开发实例
    现有一些开源ESB总线的比較
    《HTML5 从入门到精通--7.6.3 单元格垂直跨度——rowspan》
    百度究竟是哪国的公司
  • 原文地址:https://www.cnblogs.com/huangmr0811/p/5570963.html
Copyright © 2011-2022 走看看