一、测试需求描述

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

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

1、测试框架代码

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

2、项目测试代码

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

3、测试入口

  1. # -*- coding: utf-8 -*-
  2. #****************************************************************
  3. # main.py
  4. # Author     : Vince
  5. # Version    : 1.0
  6. # Date       : 2011-3-16
  7. # Description: 测试组装,用例执行入口
  8. #****************************************************************
  9. from testframe import *
  10. from xxx_server_case import *
  11. import xxx_server_case
  12. #产品系统接口测试
  13. #设置测试环境
  14. xxx_server_case.excelobj=create_excel(os.getcwd()+'/TestDir/xxx_Testcase.xls')
  15. xxx_server_case.com_ipport=xxx.com'
  16. #Add testsuite begin
  17. run("xxx_book_list", 4)
  18. #Add other suite from here
  19. #Add testsuite end
  20. statisticresult(xxx_server_case.excelobj)
  21. xxx_server_case.excelobj.close()

http接口自动化测试框架实现的更多相关文章

  1. 接口测试入门(4)--接口自动化测试框架 / list和map用法 / 随机选取新闻 (随机数生成) / 接口相关id映射

    一.接口自动化测试框架 为了更好的组织测试方法,测试用例并且持续集成,我们选择了  java+testNG(测试用例组织)+gitlab(代码版本管理)+Jenkins(持续集成工具) 作为一整套的自 ...

  2. python版接口自动化测试框架源码完整版(requests + unittest)

    python版接口自动化测试框架:https://gitee.com/UncleYong/my_rf [框架目录结构介绍] bin: 可执行文件,程序入口 conf: 配置文件 core: 核心文件 ...

  3. 接口自动化 [授客]基于python+Testlink+Jenkins实现的接口自动化测试框架V3.0

    基于python+Testlink+Jenkins实现的接口自动化测试框架V3.0   by:授客 QQ:1033553122     博客:http://blog.sina.com.cn/ishou ...

  4. 接口自动化 基于python+Testlink+Jenkins实现的接口自动化测试框架[V2.0改进版]

    基于python+Testlink+Jenkins实现的接口自动化测试框架[V2.0改进版]   by:授客 QQ:1033553122 由于篇幅问题,,暂且采用网盘分享的形式: 下载地址: [授客] ...

  5. 基于python+Testlink+Jenkins实现的接口自动化测试框架V3.0

    基于python+Testlink+Jenkins实现的接口自动化测试框架V3.0 目录 1. 开发环境2. 主要功能逻辑介绍3. 框架功能简介 4. 数据库的创建 5. 框架模块详细介绍6. Tes ...

  6. 【转】robot framework + python实现http接口自动化测试框架

    前言 下周即将展开一个http接口测试的需求,刚刚完成的java类接口测试工作中,由于之前犯懒,没有提前搭建好自动化回归测试框架,以至于后期rd每修改一个bug,经常导致之前没有问题的case又产生了 ...

  7. 【python3+request】python3+requests接口自动化测试框架实例详解教程

    转自:https://my.oschina.net/u/3041656/blog/820023 [python3+request]python3+requests接口自动化测试框架实例详解教程 前段时 ...

  8. 接口自动化 基于python实现的http+json协议接口自动化测试框架源码(实用改进版)

    基于python实现的http+json协议接口自动化测试框架(实用改进版)   by:授客 QQ:1033553122 欢迎加入软件性能测试交流QQ群:7156436     目录 1.      ...

  9. Python 基于python实现的http接口自动化测试框架(含源码)

    基于python实现的http+json协议接口自动化测试框架(含源码) by:授客 QQ:1033553122      欢迎加入软件性能测试交流 QQ群:7156436  由于篇幅问题,采用百度网 ...

  10. robot framework + python实现http接口自动化测试框架

    https://www.jianshu.com/p/6d1e8cb90e7d 前言 下周即将展开一个http接口测试的需求,刚刚完成的java类接口测试工作中,由于之前犯懒,没有提前搭建好自动化回归测 ...

随机推荐

  1. word2010没有“标题2、标题3”样式的解决办法

    word2010没有“标题2.标题3”样式的解决办法 很多人用word的时候都喜欢用“标题1”“标题2”等样式来定义他们的文档标题,被这样定义的标题会出现在导航窗格中,使浏览起来非常方便.但是最近我发 ...

  2. gradle-4.1-all.zip

    1. https://services.gradle.org/distributions/ https://services.gradle.org/distributions/gradle-4.1-a ...

  3. 使用Maven命令安装jar包到仓库中

    项目中可能会碰到很多jar包,使用maven update不能更新,或者jar包是拷贝过来,不能编译的情况.此时就需要手动使用命令行安装. 例如Demo项目中提示缺少四个jar包,但是在repo中已经 ...

  4. hdu 4746Mophues[莫比乌斯反演]

    Mophues Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 327670/327670 K (Java/Others) Total ...

  5. Asp.Net MVC大型项目实践整合 NHibernate与Json序列化

    通过NHibernate我们多表查询是实现了 但由于查询出来的集合中的对象“不是平的”,如何在送到UI绑定成了问题.ExtJs UI组件的数据绑定支持多种格式,如简单数组,Json,Xml.在本项目中 ...

  6. Spark版本发布历史,及其各版本特性

      2016年11月5日 We are proud to announce that Apache Spark won the 2016 CloudSort Benchmark (both Dayto ...

  7. parameter/argument

    根据网上一些资料,对parameter和argument的区别,做如下的简单说明.1. parameter是指函数定义中参数,而argument指的是函数调用时的实际参数.2. 简略描述为:param ...

  8. PyQT5-QSlide滑块

    """ QSlider:是一个小滑块组件,这个小滑块能够被拖着一起滑动,用于通常修改具有一定范围的数据 Author: dengyexun DateTime: 2018. ...

  9. postgresql+postgis+pgrouting安装步骤图解

    1.在此(https://www.bigsql.org/postgresql/installers.jsp/)下载postgresql(开源数据库,gis行业推荐使用); 2.在此(http://wi ...

  10. 关于LeNet-5卷积神经网络 S2层与C3层连接的参数计算的思考???

    https://blog.csdn.net/saw009/article/details/80590245 关于LeNet-5卷积神经网络 S2层与C3层连接的参数计算的思考??? 首先图1是LeNe ...