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

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

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

1、测试框架代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

#****************************************************************

# 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、项目测试代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

# -*- 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、测试入口

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

# -*- 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()

​现在我也找了很多测试的朋友,做了一个分享技术的交流群,共享了很多我们收集的技术文档和视频教程。
如果你不想再体验自学时找不到资源,没人解答问题,坚持几天便放弃的感受
qq群号:485187702【暗号:csdn11】
可以加入我们一起交流。而且还有很多在自动化,性能,安全,测试开发等等方面有一定建树的技术大牛
分享他们的经验,还会分享很多直播讲座和技术沙龙
可以免费学习!划重点!开源的!!!
视频+文档+PDF+面试题可以关注公众号:【软件测试小dao】

最后感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走! 希望能帮助到你!【100%无套路免费领取】

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值