http接口自动化测试框架实现

http接口自动化测试框架实现

作者:张元礼

http://blog.csdn.net/vincetest

一、测试需求描述

对服务后台一系列的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表格样式

54765_13034565308dlz

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

1、测试框架代码

view plaincopy to clipboardprint?
01.#****************************************************************   
02.# TestFrame.py   
03.# Author     : Vince   
04.# Version    : 1.1.2   
05.# Date       : 2011-3-14   
06.# Description: 自动化测试平台   
07.#****************************************************************   
08.  
09.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、项目测试代码

view plaincopy to clipboardprint?
01.# -*- coding: utf-8 -*-   
02.#****************************************************************   
03.# xxx_server_case.py   
04.# Author     : Vince   
05.# Version    : 1.0   
06.# Date       : 2011-3-10   
07.# Description: 内容服务系统测试代码   
08.#****************************************************************   
09.  
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、测试入口

view plaincopy to clipboardprint?
01.# -*- coding: utf-8 -*-   
02.#****************************************************************   
03.# main.py   
04.# Author     : Vince   
05.# Version    : 1.0   
06.# Date       : 2011-3-16   
07.# Description: 测试组装,用例执行入口   
08.#****************************************************************   
09.  
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()  

最后感谢我的同事Roger为此做了一些优化,后续优化的东东还很多,我们一直在努力!

欢迎转载此文,转载时请注明文章来源:张元礼的博客 http://blog.csdn.net/vincetest

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/vincetest/archive/2011/04/22/6341658.aspx#1655236

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值