Python http接口自动化测试框架实现方法示例


Posted in Python onDecember 06, 2018

本文实例讲述了Python 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表格样式

Python http接口自动化测试框架实现方法示例

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

1、测试框架代码

#****************************************************************
# TestFrame.py
# Author   : Vince
# Version  : 1.1.2
# Date    : 2011-3-14
# Description: 自动化测试平台
#****************************************************************
import os,sys, urllib, httplib, profile, datetime, time
from xml2dict import XML2Dict
import win32com.client
from win32com.client import Dispatch
import xml.etree.ElementTree as et
#import MySQLdb
#Excel表格中测试结果底色
OK_COLOR=0xffffff
NG_COLOR=0xff
#NT_COLOR=0xffff
NT_COLOR=0xC0C0C0
#Excel表格中测试结果汇总显示位置
TESTTIME=[1, 14]
TESTRESULT=[2, 14]
#Excel模版设置
#self.titleindex=3    #Excel中测试用例标题行索引
#self.casebegin =4    #Excel中测试用例开始行索引
#self.argbegin  =3    #Excel中参数开始列索引
#self.argcount =8    #Excel中支持的参数个数
class create_excel:
  def __init__(self, sFile, dtitleindex=3, dcasebegin=4, dargbegin=3, dargcount=8):
    self.xlApp = win32com.client.Dispatch('et.Application')  #MS:Excel WPS:et
    try:
      self.book = self.xlApp.Workbooks.Open(sFile)
    except:
      print_error_info()
      print "打开文件失败"
      exit()
    self.file=sFile
    self.titleindex=dtitleindex
    self.casebegin=dcasebegin
    self.argbegin=dargbegin
    self.argcount=dargcount
    self.allresult=[]
    self.retCol=self.argbegin+self.argcount
    self.xmlCol=self.retCol+1
    self.resultCol=self.xmlCol+1
  def close(self):
    #self.book.Close(SaveChanges=0)
    self.book.Save()
    self.book.Close()
    #self.xlApp.Quit()
    del self.xlApp
  def read_data(self, iSheet, iRow, iCol):
    try:
      sht = self.book.Worksheets(iSheet)
      sValue=str(sht.Cells(iRow, iCol).Value)
    except:
      self.close()
      print('读取数据失败')
      exit()
    #去除'.0'
    if sValue[-2:]=='.0':
      sValue = sValue[0:-2]
    return sValue
  def write_data(self, iSheet, iRow, iCol, sData, color=OK_COLOR):
    try:
      sht = self.book.Worksheets(iSheet)
      sht.Cells(iRow, iCol).Value = sData.decode("utf-8")
      sht.Cells(iRow, iCol).Interior.Color=color
      self.book.Save()
    except:
      self.close()
      print('写入数据失败')
      exit()
  #获取用例个数
  def get_ncase(self, iSheet):
    try:
      return self.get_nrows(iSheet)-self.casebegin+1
    except:
      self.close()
      print('获取Case个数失败')
      exit()
  def get_nrows(self, iSheet):
    try:
      sht = self.book.Worksheets(iSheet)
      return sht.UsedRange.Rows.Count
    except:
      self.close()
      print('获取nrows失败')
      exit()
  def get_ncols(self, iSheet):
    try:
      sht = self.book.Worksheets(iSheet)
      return sht.UsedRange.Columns.Count
    except:
      self.close()
      print('获取ncols失败')
      exit()
  def del_testrecord(self, suiteid):
    try:
      #为提升性能特别从For循环提取出来
      nrows=self.get_nrows(suiteid)+1
      ncols=self.get_ncols(suiteid)+1
      begincol=self.argbegin+self.argcount
      #提升性能
      sht = self.book.Worksheets(suiteid)
      for row in range(self.casebegin, nrows):
        for col in range(begincol, ncols):
          str=self.read_data(suiteid, row, col)
          #清除实际结果[]
          startpos = str.find('[')
          if startpos>0:
            str = str[0:startpos].strip()
            self.write_data(suiteid, row, col, str, OK_COLOR)
          else:
            #提升性能
            sht.Cells(row, col).Interior.Color = OK_COLOR
        #清除TestResul列中的测试结果,设置为NT
        self.write_data(suiteid, row, self.argbegin+self.argcount+1, ' ', OK_COLOR)
        self.write_data(suiteid, row, self.resultCol, 'NT', NT_COLOR)
    except:
      self.close()
      print('清除数据失败')
      exit()
#执行调用
def HTTPInvoke(IPPort, url):
  conn = httplib.HTTPConnection(IPPort)
  conn.request("GET", url)
  rsps = conn.getresponse()
  data = rsps.read()
  conn.close()
  return data
#获取用例基本信息[Interface,argcount,[ArgNameList]]
def get_caseinfo(Data, SuiteID):
  caseinfolist=[]
  sInterface=Data.read_data(SuiteID, 1, 2)
  argcount=int(Data.read_data(SuiteID, 2, 2))
  #获取参数名存入ArgNameList
  ArgNameList=[]
  for i in range(0, argcount):
    ArgNameList.append(Data.read_data(SuiteID, Data.titleindex, Data.argbegin+i))
  caseinfolist.append(sInterface)
  caseinfolist.append(argcount)
  caseinfolist.append(ArgNameList)
  return caseinfolist
#获取输入
def get_input(Data, SuiteID, CaseID, caseinfolist):
  sArge=''
  #参数组合
  for j in range(0, caseinfolist[1]):
    if Data.read_data(SuiteID, Data.casebegin+CaseID, Data.argbegin+j) != "None":
      sArge=sArge+caseinfolist[2][j]+'='+Data.read_data(SuiteID, Data.casebegin+CaseID, Data.argbegin+j)+'&'
  #去掉结尾的&字符
  if sArge[-1:]=='&':
    sArge = sArge[0:-1]
  sInput=caseinfolist[0]+sArge  #组合全部参数
  return sInput
#结果判断
def assert_result(sReal, sExpect):
  sReal=str(sReal)
  sExpect=str(sExpect)
  if sReal==sExpect:
    return 'OK'
  else:
    return 'NG'
#将测试结果写入文件
def write_result(Data, SuiteId, CaseId, resultcol, *result):
  if len(result)>1:
    ret='OK'
    for i in range(0, len(result)):
      if result[i]=='NG':
        ret='NG'
        break
    if ret=='NG':
      Data.write_data(SuiteId, Data.casebegin+CaseId, resultcol,ret, NG_COLOR)
    else:
      Data.write_data(SuiteId, Data.casebegin+CaseId, resultcol,ret, OK_COLOR)
    Data.allresult.append(ret)
  else:
    if result[0]=='NG':
      Data.write_data(SuiteId, Data.casebegin+CaseId, resultcol,result[0], NG_COLOR)
    elif result[0]=='OK':
      Data.write_data(SuiteId, Data.casebegin+CaseId, resultcol,result[0], OK_COLOR)
    else: #NT
      Data.write_data(SuiteId, Data.casebegin+CaseId, resultcol,result[0], NT_COLOR)
    Data.allresult.append(result[0])
  #将当前结果立即打印
  print 'case'+str(CaseId+1)+':', Data.allresult[-1]
#打印测试结果
def statisticresult(excelobj):
  allresultlist=excelobj.allresult
  count=[0, 0, 0]
  for i in range(0, len(allresultlist)):
    #print 'case'+str(i+1)+':', allresultlist[i]
    count=countflag(allresultlist[i],count[0], count[1], count[2])
  print 'Statistic result as follow:'
  print 'OK:', count[0]
  print 'NG:', count[1]
  print 'NT:', count[2]
#解析XmlString返回Dict
def get_xmlstring_dict(xml_string):
  xml = XML2Dict()
  return xml.fromstring(xml_string)
#解析XmlFile返回Dict
def get_xmlfile_dict(xml_file):
  xml = XML2Dict()
  return xml.parse(xml_file)
#去除历史数据expect[real]
def delcomment(excelobj, suiteid, iRow, iCol, str):
  startpos = str.find('[')
  if startpos>0:
    str = str[0:startpos].strip()
    excelobj.write_data(suiteid, iRow, iCol, str, OK_COLOR)
  return str
#检查每个item (非结构体)
def check_item(excelobj, suiteid, caseid,real_dict, checklist, begincol):
  ret='OK'
  for checkid in range(0, len(checklist)):
    real=real_dict[checklist[checkid]]['value']
    expect=excelobj.read_data(suiteid, excelobj.casebegin+caseid, begincol+checkid)
    #如果检查不一致测将实际结果写入expect字段,格式:expect[real]
    #将return NG
    result=assert_result(real, expect)
    if result=='NG':
      writestr=expect+'['+real+']'
      excelobj.write_data(suiteid, excelobj.casebegin+caseid, begincol+checkid, writestr, NG_COLOR)
      ret='NG'
  return ret
#检查结构体类型
def check_struct_item(excelobj, suiteid, caseid,real_struct_dict, structlist, structbegin, structcount):
  ret='OK'
  if structcount>1: #传入的是List
    for structid in range(0, structcount):
      structdict=real_struct_dict[structid]
      temp=check_item(excelobj, suiteid, caseid,structdict, structlist, structbegin+structid*len(structlist))
      if temp=='NG':
        ret='NG'
  else: #传入的是Dict
    temp=check_item(excelobj, suiteid, caseid,real_struct_dict, structlist, structbegin)
    if temp=='NG':
      ret='NG'
  return ret
#获取异常函数及行号
def print_error_info():
  """Return the frame object for the caller's stack frame."""
  try:
    raise Exception
  except:
    f = sys.exc_info()[2].tb_frame.f_back
  print (f.f_code.co_name, f.f_lineno)
#测试结果计数器,类似Switch语句实现
def countflag(flag,ok, ng, nt):
  calculation = {'OK':lambda:[ok+1, ng, nt],
             'NG':lambda:[ok, ng+1, nt],
             'NT':lambda:[ok, ng, nt+1]}
  return calculation[flag]()

2、项目测试代码

# -*- coding: utf-8 -*-
#****************************************************************
# xxx_server_case.py
# Author   : Vince
# Version  : 1.0
# Date    : 2011-3-10
# Description: 内容服务系统测试代码
#****************************************************************
from testframe import *
from common_lib import *
httpString='http://xxx.com/xxx_product/test/'
expectXmldir=os.getcwd()+'/TestDir/expect/'
realXmldir=os.getcwd()+'/TestDir/real/'
def run(interface_name, suiteid):
  print '【'+interface_name+'】' + ' Test Begin,please waiting...'
  global expectXmldir, realXmldir
  #根据接口名分别创建预期结果目录和实际结果目录
  expectDir=expectXmldir+interface_name
  realDir=realXmldir+interface_name
  if os.path.exists(expectDir) == 0:
    os.makedirs(expectDir)
  if os.path.exists(realDir) == 0:
    os.makedirs(realDir)
  excelobj.del_testrecord(suiteid) #清除历史测试数据
  casecount=excelobj.get_ncase(suiteid) #获取case个数
  caseinfolist=get_caseinfo(excelobj, suiteid) #获取Case基本信息
  #遍历执行case
  for caseid in range(0, casecount):
    #检查是否执行该Case
    if excelobj.read_data(suiteid,excelobj.casebegin+caseid, 2)=='N':
      write_result(excelobj, suiteid, caseid, excelobj.resultCol, 'NT')
      continue #当前Case结束,继续执行下一个Case
    #获取测试数据
    sInput=httpString+get_input(excelobj, suiteid, caseid, caseinfolist)
    XmlString=HTTPInvoke(com_ipport, sInput)   #执行调用
    #获取返回码并比较
    result_code=et.fromstring(XmlString).find("result_code").text
    ret1=check_result(excelobj, suiteid, caseid,result_code, excelobj.retCol)
    #保存预期结果文件
    expectPath=expectDir+'/'+str(caseid+1)+'.xml'
    #saveXmlfile(expectPath, XmlString)
    #保存实际结果文件
    realPath=realDir+'/'+str(caseid+1)+'.xml'
    saveXmlfile(realPath, XmlString)
    #比较预期结果和实际结果
    ret2= check_xmlfile(excelobj, suiteid, caseid,expectPath, realPath)
    #写测试结果
    write_result(excelobj, suiteid, caseid, excelobj.resultCol, ret1, ret2)
  print '【'+interface_name+'】' + ' Test End!'

3、测试入口

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

更多关于Python相关内容可查看本站专题:《Python Socket编程技巧总结》、《Python数据结构与算法教程》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》、《Python入门与进阶经典教程》及《Python文件与目录操作技巧汇总》

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
python实现代码行数统计示例分享
Feb 10 Python
Python实现两款计算器功能示例
Dec 19 Python
Django框架模板语言实例小结【变量,标签,过滤器,继承,html转义】
May 23 Python
python自动化测试之如何解析excel文件
Jun 27 Python
python卸载后再次安装遇到的问题解决
Jul 10 Python
Django 允许局域网中的机器访问你的主机操作
May 13 Python
解决pycharm debug时界面下方不出现step等按钮及变量值的问题
Jun 09 Python
Python定义一个函数的方法
Jun 15 Python
python中逻辑与或(and、or)和按位与或异或(&、|、^)区别
Aug 05 Python
使用Python将语音转换为文本的方法
Aug 10 Python
Python MNIST手写体识别详解与试练
Nov 07 Python
Python中使用tkFileDialog实现文件选择、保存和路径选择
May 20 Python
python的常用模块之collections模块详解
Dec 06 #Python
Django管理员账号和密码忘记的完美解决方法
Dec 06 #Python
Python操作json的方法实例分析
Dec 06 #Python
Python多线程应用于自动化测试操作示例
Dec 06 #Python
Python实现多属性排序的方法
Dec 05 #Python
python通过ffmgep从视频中抽帧的方法
Dec 05 #Python
Python中xml和json格式相互转换操作示例
Dec 05 #Python
You might like
php 删除数组元素
2009/01/16 PHP
php截取字符串并保留完整xml标签的函数代码
2013/02/06 PHP
ThinkPHP写数组插入与获取最新插入数据ID实例
2014/11/03 PHP
Laravel 5 框架入门(四)完结篇
2015/04/09 PHP
10款实用的PHP开源工具
2015/10/23 PHP
Symfony实现行为和模板中取得request参数的方法
2016/03/17 PHP
PHP实现通过文本文件统计页面访问量功能示例
2019/02/13 PHP
用JavaScript获取网页中的js、css、Flash等文件
2006/12/20 Javascript
JavaScript 自动完成脚本整理(33个)
2009/10/20 Javascript
基于jquery实现的定时显示与隐藏div广告的实现代码
2013/08/22 Javascript
浅谈javascript中return语句
2015/07/15 Javascript
javascript中字体浮动效果的简单实例演示
2015/11/18 Javascript
Javascript将数字转化成为货币格式字符串
2016/06/22 Javascript
jQuery实现带延时功能的水平多级菜单效果【附demo源码下载】
2016/09/21 Javascript
JS简单实现自定义右键菜单实例
2017/05/31 Javascript
Node.js微信 access_token ( jsapi_ticket ) 存取与刷新的示例
2017/09/30 Javascript
vue init webpack myproject构建项目 ip不能访问的解决方法
2018/03/20 Javascript
mockjs+vue页面直接展示数据的方法
2018/12/19 Javascript
jQuery位置选择器用法实例分析
2019/06/28 jQuery
详细分析vue表单数据的绑定
2020/07/20 Javascript
[49:27]LGD vs OG 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
示例详解Python3 or Python2 两者之间的差异
2018/08/23 Python
Python字典遍历操作实例小结
2019/03/05 Python
Tensorflow 使用pb文件保存(恢复)模型计算图和参数实例详解
2020/02/11 Python
python操作yaml说明
2020/04/08 Python
Python 高效编程技巧分享
2020/09/10 Python
CSS3感应鼠标的背景闪烁和图片缩放动画效果
2014/05/14 HTML / CSS
瑜伽服装品牌:露露柠檬(lululemon athletica)
2017/06/04 全球购物
Holiday Inn中国官网:IHG旗下假日酒店预订
2018/04/08 全球购物
什么是事务?事务有哪些性质?
2012/03/11 面试题
数学专业推荐信范文
2013/11/21 职场文书
高三英语教学反思
2014/01/13 职场文书
自考毕业自我鉴定
2014/03/18 职场文书
小学生法制教育心得体会
2016/01/14 职场文书
Apache Hudi数据布局黑科技降低一半查询时间
2022/03/31 Servers
vue修饰符.capture和.self的区别
2022/04/22 Vue.js