Python + requests实现接口自动化框架!

为什么要做接口自动化框架

1、业务与配置的分离

2、数据与程序的分离;数据的变更不影响程序

3、有日志功能,实现无人值守

4、自动发送测试报告

5、不懂编程的测试人员也可以进行测试

正常接口测试的流程是什么?

确定接口测试使用的工具----->配置需要的接口参数----->进行测试----->检查测试结果----->生成测试报告

测试的工具:python+requests

接口测试用例:excel

一、接口框架如下:

1、action包:用来存放关键字函数

2、config包:用来存放配置文件

3、TestData:用来存放测试数据,excel表

4、Log包:用来存放日志文件

5、utils包:用来存放公共的类

6、运行主程序interface_auto_test.py

7、Readme.txt:告诉团队组员使用改框架需要注意的地方

二、接口的数据规范设计---Case设计

一个sheet对应数据库里面一张表

APIsheet存放
编号;从1开始
接口的名称(APIName);
请求的url(RequestUrl);
请求的方法(RequestMethod);
传参的方式(paramsType):post/get请求方法不一样
用例说明(APITestCase)
是否执行(Active)部分接口已测通,下次不用测试,直接把这里设置成N,跳过此接口

post与get的区别

查看post详情

post请求参数一般是json串,参数放在from表单里面;参数一般不可见,相对来说安全性高些

查看get详情

get请求参数一般直接放在url里面

2.1注册接口用例

RequestData:请求的数据
(开发制定的传参方式)
RelyData:数据依赖
ResponseCode:响应code
ResponseData:响应数据
DataStore:存储的依赖数据;如果存在数据库里面,在表里增加一个字段用来存依赖的数据
(存储的方式是编写接口自动化的人员来设定的存储方式)
CheckPoint:检查点
Active:是否执行
Status:执行用例的状态,方便查看用例是否执行成功
ErrorInfo:case运行失败,失败的错误信息;eg:是也本身的原因还是case设置失败,还是其他原因

2.2登录接口用例

RequestData:请求的数据
(开发制定的传参方式)
RelyData:数据依赖
(存储的方式是编写接口自动化的人员来设定的存储方式)
ResponseCode:响应code
ResponseData:响应数据
DataStore:存储的依赖数据;如果存在数据库里面,在表里增加一个字段用来存依赖的数据
(存储的方式是编写接口自动化的人员来设定的存储方式)
CheckPoint:检查点
Active:是否执行
Status:执行用例的状态,方便查看用例是否执行成功
ErrorInfo:case运行失败,失败的错误信息;eg:是也本身的原因还是case设置失败,还是其他原因

重点说明下RelyData:数据依赖
采取的是字典:key:value来存储数据格式;

{"request":{"username":"register->1","password":"register->1"},"response":{"code":"register->1"}}

格式化之后:

 
  1. {

  2. "request":{

  3. "username":"register->1",

  4. "password":"register->1"

  5. },

  6. "response":{

  7. "code":"register->1"

  8. }

  9. }

三、创建utils包:用来存放公共的类
3.1 ParseExcel.py 操作封装excel的类(ParseExcel.py)

 
  1. #encoding=utf-8

  2. import openpyxl

  3. from openpyxl.styles import Border, Side, Font

  4. import time

  5. class ParseExcel(object):

  6. def __init__(self):

  7. self.workbook = None

  8. self.excelFile = None

  9. self.font = Font(color = None) # 设置字体的颜色

  10. # 颜色对应的RGB值

  11. self.RGBDict = {'red': 'FFFF3030', 'green': 'FF008B00'}

  12. def loadWorkBook(self, excelPathAndName):

  13. # 将excel文件加载到内存,并获取其workbook对象

  14. try:

  15. self.workbook = openpyxl.load_workbook(excelPathAndName)

  16. except Exception as err:

  17. raise err

  18. self.excelFile = excelPathAndName

  19. return self.workbook

  20. def getSheetByName(self, sheetName):

  21. # 根据sheet名获取该sheet对象

  22. try:

  23. # sheet = self.workbook.get_sheet_by_name(sheetName)

  24. sheet = self.workbook[sheetName]

  25. return sheet

  26. except Exception as err:

  27. raise err

  28. def getSheetByIndex(self, sheetIndex):

  29. # 根据sheet的索引号获取该sheet对象

  30. try:

  31. # sheetname = self.workbook.get_sheet_names()[sheetIndex]

  32. sheetname = self.workbook.sheetnames[sheetIndex]

  33. except Exception as err:

  34. raise err

  35. # sheet = self.workbook.get_sheet_by_name(sheetname)

  36. sheet = self.workbook[sheetname]

  37. return sheet

  38. def getRowsNumber(self, sheet):

  39. # 获取sheet中有数据区域的结束行号

  40. return sheet.max_row

  41. def getColsNumber(self, sheet):

  42. # 获取sheet中有数据区域的结束列号

  43. return sheet.max_column

  44. def getStartRowNumber(self, sheet):

  45. # 获取sheet中有数据区域的开始的行号

  46. return sheet.min_row

  47. def getStartColNumber(self, sheet):

  48. # 获取sheet中有数据区域的开始的列号

  49. return sheet.min_column

  50. def getRow(self, sheet, rowNo):

  51. # 获取sheet中某一行,返回的是这一行所有的数据内容组成的tuple,

  52. # 下标从1开始,sheet.rows[1]表示第一行

  53. try:

  54. rows = []

  55. for row in sheet.iter_rows():

  56. rows.append(row)

  57. return rows[rowNo - 1]

  58. except Exception as err:

  59. raise err

  60. def getColumn(self, sheet, colNo):

  61. # 获取sheet中某一列,返回的是这一列所有的数据内容组成tuple,

  62. # 下标从1开始,sheet.columns[1]表示第一列

  63. try:

  64. cols = []

  65. for col in sheet.iter_cols():

  66. cols.append(col)

  67. return cols[colNo - 1]

  68. except Exception as err:

  69. raise err

  70. def getCellOfValue(self, sheet, coordinate = None,

  71. rowNo = None, colsNo = None):

  72. # 根据单元格所在的位置索引获取该单元格中的值,下标从1开始,

  73. # sheet.cell(row = 1, column = 1).value,

  74. # 表示excel中第一行第一列的值

  75. if coordinate != None:

  76. try:

  77. return sheet[coordinate]

  78. except Exception as err:

  79. raise err

  80. elif coordinate is None and rowNo is not None and \

  81. colsNo is not None:

  82. try:

  83. return sheet.cell(row = rowNo, column = colsNo).value

  84. except Exception as err:

  85. raise err

  86. else:

  87. raise Exception("Insufficient Coordinates of cell !")

  88. def getCellOfObject(self, sheet, coordinate = None,

  89. rowNo = None, colsNo = None):

  90. # 获取某个单元格的对象,可以根据单元格所在位置的数字索引,

  91. # 也可以直接根据excel中单元格的编码及坐标

  92. # 如getCellObject(sheet, coordinate = 'A1') or

  93. # getCellObject(sheet, rowNo = 1, colsNo = 2)

  94. if coordinate != None:

  95. try:

  96. # return sheet.cell(coordinate = coordinate)

  97. return sheet[coordinate]

  98. except Exception as err:

  99. raise err

  100. elif coordinate == None and rowNo is not None and \

  101. colsNo is not None:

  102. try:

  103. return sheet.cell(row = rowNo,column = colsNo)

  104. except Exception as err:

  105. raise err

  106. else:

  107. raise Exception("Insufficient Coordinates of cell !")

  108. def writeCell(self, sheet, content, coordinate = None,

  109. rowNo = None, colsNo = None, style = None):

  110. #根据单元格在excel中的编码坐标或者数字索引坐标向单元格中写入数据,

  111. # 下标从1开始,参style表示字体的颜色的名字,比如red,green

  112. if coordinate is not None:

  113. try:

  114. # sheet.cell(coordinate = coordinate).value = content

  115. sheet[coordinate] = content

  116. if style is not None:

  117. sheet[coordinate].\

  118. font = Font(color = self.RGBDict[style])

  119. self.workbook.save(self.excelFile)

  120. except Exception as e:

  121. raise e

  122. elif coordinate == None and rowNo is not None and \

  123. colsNo is not None:

  124. try:

  125. sheet.cell(row = rowNo,column = colsNo).value = content

  126. if style:

  127. sheet.cell(row = rowNo,column = colsNo).\

  128. font = Font(color = self.RGBDict[style])

  129. self.workbook.save(self.excelFile)

  130. except Exception as e:

  131. raise e

  132. else:

  133. raise Exception("Insufficient Coordinates of cell !")

  134. def writeCellCurrentTime(self, sheet, coordinate = None,

  135. rowNo = None, colsNo = None):

  136. # 写入当前的时间,下标从1开始

  137. now = int(time.time()) #显示为时间戳

  138. timeArray = time.localtime(now)

  139. currentTime = time.strftime("%Y-%m-%d %H:%M:%S", timeArray)

  140. if coordinate is not None:

  141. try:

  142. sheet.cell(coordinate = coordinate).value = currentTime

  143. self.workbook.save(self.excelFile)

  144. except Exception as e:

  145. raise e

  146. elif coordinate == None and rowNo is not None \

  147. and colsNo is not None:

  148. try:

  149. sheet.cell(row = rowNo, column = colsNo

  150. ).value = currentTime

  151. self.workbook.save(self.excelFile)

  152. except Exception as e:

  153. raise e

  154. else:

  155. raise Exception("Insufficient Coordinates of cell !")

  156. if __name__ == '__main__':

  157. # 测试代码

  158. pe = ParseExcel()

  159. pe.loadWorkBook(r'D:\ProgramSourceCode\Python Source Code\WorkSpace\InterfaceFrame2018\inter_test_data.xlsx')

  160. sheetObj = pe.getSheetByName(u"API")

  161. print("通过名称获取sheet对象的名字:", sheetObj.title)

  162. # print help(sheetObj.rows)

  163. print("通过index序号获取sheet对象的名字:", pe.getSheetByIndex(0).title)

  164. sheet = pe.getSheetByIndex(0)

  165. print(type(sheet))

  166. print(pe.getRowsNumber(sheet)) #获取最大行号

  167. print(pe.getColsNumber(sheet)) #获取最大列号

  168. rows = pe.getRow(sheet, 1) #获取第一行

  169. for i in rows:

  170. print(i.value)

  171. # # 获取第一行第一列单元格内容

  172. # print pe.getCellOfValue(sheet, rowNo = 1, colsNo = 1)

  173. # pe.writeCell(sheet, u'我爱祖国', rowNo = 10, colsNo = 10)

  174. # pe.writeCellCurrentTime(sheet, rowNo = 10, colsNo = 11)

  1. 现在我也找了很多测试的朋友,做了一个分享技术的交流群,共享了很多我们收集的技术文档和视频教程。

  2. 如果你不想再体验自学时找不到资源,没人解答问题,坚持几天便放弃的感受

  3. 可以加入我们一起交流。而且还有很多在自动化,性能,安全,测试开发等等方面有一定建树的技术大牛

  4. 分享他们的经验,还会分享很多直播讲座和技术沙龙

  5. 可以免费学习!划重点!开源的!!!

  6. qq群号:680748947

3.2 封装get/post请求(HttpClient.py)

  1. import requests

  2. import json

  3. class HttpClient(object):

  4. def __init__(self):

  5. pass

  6. def request(self, requestMethod, requestUrl, paramsType,

  7. requestData, headers =None, **kwargs):

  8. if requestMethod == "post":

  9. print("---", requestData, type(requestData))

  10. if paramsType == "form":

  11. response = self.__post(url = requestUrl, data = json.dumps(eval(requestData)),

  12. headers = headers, **kwargs)

  13. return response

  14. elif paramsType == "json":

  15. response = self.__post(url = requestUrl, json = json.dumps(eval(requestData)),

  16. headers = headers, **kwargs)

  17. return response

  18. elif requestMethod == "get":

  19. request_url = requestUrl

  20. if paramsType == "url":

  21. request_url = "%s%s" %(requestUrl, requestData)

  22. response = self.__get(url = request_url, params = requestData, **kwargs)

  23. return response

  24. def __post(self, url, data = None, json = None, headers=None,**kwargs):

  25. print("----")

  26. response = requests.post(url=url, data = data, json=json, headers=headers)

  27. return response

  28. def __get(self, url, params = None, **kwargs):

  29. response = requests.get(url, params = params, **kwargs)

  30. return response

  31. if __name__ == "__main__":

  32. hc = HttpClient()

  33. res = hc.request("get", "http://39.106.41.11:8080/getBlogContent/", "url",'2')

  34. print(res.json())

3.3 封装MD5(md5_encrypt)
  1. import hashlib

  2. def md5_encrypt(text):

  3. m5 = hashlib.md5()

  4. m5.update(text.encode("utf-8"))

  5. value = m5.hexdigest()

  6. return value

  7. if __name__ == "__main__":

  8. print(md5_encrypt("sfwe"))

3.4 封装Log
  1. import logging

  2. import logging.config

  3. from config.public_data import baseDir

  4. # 读取日志配置文件

  5. logging.config.fileConfig(baseDir + "\config\Logger.conf")

  6. # 选择一个日志格式

  7. logger = logging.getLogger("example02")#或者example01

  8. def debug(message):

  9. # 定义dubug级别日志打印方法

  10. logger.debug(message)

  11. def info(message):

  12. # 定义info级别日志打印方法

  13. logger.info(message)

  14. def warning(message):

  15. # 定义warning级别日志打印方法

  16. logger.warning(message)

3.5 封装发送Email类
  1. import smtplib

  2. from email.mime.text import MIMEText

  3. from email.mime.multipart import MIMEMultipart

  4. from email.header import Header

  5. from ProjVar.var import *

  6. import os

  7. import smtplib

  8. from email import encoders

  9. from email.mime.base import MIMEBase

  10. from email.mime.text import MIMEText

  11. from email.mime.multipart import MIMEMultipart

  12. from email.header import Header

  13. from email.utils import formataddr

  14. def send_mail():

  15. mail_host="smtp.qq.com" #设置服务器

  16. mail_user="xiangxiang" #用户名

  17. mail_pass="cmxx" #口令

  18. sender = 'cm2019@126.com'

  19. receivers = ['672014873@qq.com',"cm2019@126.com"] # 接收邮件,可设置为你的QQ邮箱或者其他邮箱

  20. # 创建一个带附件的实例

  21. message = MIMEMultipart()

  22. message['From'] = formataddr(["自动化测试", "cm2019@126.com"])

  23. message['To'] = ','.join(receivers)

  24. subject = '自动化测试执行报告'

  25. message['Subject'] = Header(subject, 'utf-8')

  26. message["Accept-Language"]="zh-CN"

  27. message["Accept-Charset"]="ISO-8859-1,utf-8,gbk"

  28. # 邮件正文内容

  29. message.attach(MIMEText('最新执行的自动化测试报告,请参阅附件内容!', 'plain', 'utf-8'))

  30. # 构造附件1,传送测试结果的excel文件

  31. att = MIMEBase('application', 'octet-stream')

  32. att.set_payload(open(ProjDirPath+"\\testdata\\testdata.xlsx", 'rb').read())

  33. att.add_header('Content-Disposition', 'attachment', filename=('gbk', '', "自动化测试报告.xlsx"))

  34. encoders.encode_base64(att)

  35. message.attach(att)

  36. """

  37. # 构造附件2,传送当前目录下的 runoob.txt 文件

  38. att2 = MIMEText(open('e:\\a.py','rb').read(), 'base64', 'utf-8')

  39. att2["Content-Type"] = 'application/octet-stream'

  40. att2["Content-Disposition"] = 'attachment; filename="a.py"'

  41. message.attach(att2)

  42. """

  43. try:

  44. smtpObj = smtplib.SMTP(mail_host)

  45. smtpObj.login(mail_user, mail_pass)

  46. smtpObj.sendmail(sender, receivers, message.as_string())

  47. print("邮件发送成功")

  48. except smtplib.SMTPException as e:

  49. print("Error: 无法发送邮件", e)

  50. if __name__ == "__main__":

  51. send_mail()

四、 创建config包 用来存放公共的参数、配置文件、长时间不变的变量值

创建public_data.p

  1. import os

  2. # 整个项目的根目录绝对路劲

  3. baseDir = os.path.dirname(os.path.dirname(__file__))

  4. # 获取测试数据文件的绝对路径

  5. file_path = baseDir + "/TestData/inter_test_data.xlsx"

  6. API_apiName = 2

  7. API_requestUrl = 3

  8. API_requestMothod = 4

  9. API_paramsType = 5

  10. API_apiTestCaseFileName = 6

  11. API_active = 7

  12. CASE_requestData = 1

  13. CASE_relyData = 2

  14. CASE_responseCode = 3

  15. CASE_responseData = 4

  16. CASE_dataStore = 5

  17. CASE_checkPoint = 6

  18. CASE_active = 7

  19. CASE_status = 8

  20. CASE_errorInfo = 9

  21. # 存储请求参数里面依赖的数据

  22. REQUEST_DATA = {}

  23. # 存储响应对象中的依赖数据

  24. RESPONSE_DATA = {}

  25. if __name__=="__main__":

  26. print(file_path)

  27. print(baseDir)

五、创建TestData目录,用来存放测试文件

inter_test_data.xlsx

六、创建action包,用来存放关键字函数
6.1 解决数据依赖 (GetRely.py)

  1. from config.public_data import REQUEST_DATA, RESPONSE_DATA

  2. from utils.md5_encrypt import md5_encrypt

  3. REQUEST_DATA = {"用户注册":{"1":{"username":"zhangsan", "password":"dfsdf23"},

  4. "headers":{"cookie":"asdfwerw"}}}

  5. RESPONSE_DATA = {"用户注册":{"1":{"code":"00"}, "headers":{"age":2342}}}

  6. class GetRely(object):

  7. def __init__(self):

  8. pass

  9. @classmethod

  10. def get(self, dataSource, relyData, headSource = {}):

  11. print(type(dataSource))

  12. print(dataSource)

  13. data = dataSource.copy()

  14. for key, value in relyData.items():

  15. if key == "request":

  16. #说明应该去REQUEST_DATA中获取

  17. for k, v in value.items():

  18. interfaceName, case_idx = v.split("->")

  19. val = REQUEST_DATA[interfaceName][case_idx][k]

  20. if k == "password":

  21. data[k] = md5_encrypt(val)

  22. else:

  23. data[k] = val

  24. elif key == "response":

  25. # 应该去RESPONSE_DATA中获取

  26. for k, v in value.items():

  27. interfaceName, case_idx = v.split("->")

  28. data[k] = RESPONSE_DATA[interfaceName][case_idx][k]

  29. elif key == "headers":

  30. if headSource:

  31. for key, value in value.items():

  32. if key == "request":

  33. for k, v in value.items():

  34. for i in v:

  35. headSource[i] = REQUEST_DATA[k]["headers"][i]

  36. elif key == "response":

  37. for i, val in value.items():

  38. for j in val:

  39. headSource[j] = RESPONSE_DATA[i]["headers"][j]

  40. return "%s" %data

  41. if __name__ == "__main__":

  42. s = {"username": "", "password": "","code":""}

  43. h = {"cookie":"123", "age":332}

  44. rely = {"request": {"username": "用户注册->1", "password": "用户注册->1"},

  45. "response":{"code":"用户注册->1"},

  46. "headers":{"request":{"用户注册":["cookie"]},"response":{"用户注册":["age"]}}

  47. }

  48. print(GetRely.get(s, rely, h))

6.2 解决数据存储(RelyDataStore.y)

  1. from config.public_data import RESPONSE_DATA, REQUEST_DATA

  2. class RelyDataStore(object):

  3. def __init__(self):

  4. pass

  5. @classmethod

  6. def do(cls, storePoint, apiName, caseId, request_source = {}, response_source = {}, req_headers={}, res_headers = {}):

  7. for key, value in storePoint.items():

  8. if key == "request":

  9. # 说明需要存储的依赖数据来自请求参数,应该将数据存储到REQUEST_DATA

  10. for i in value:

  11. if i in request_source:

  12. val = request_source[i]

  13. if apiName not in REQUEST_DATA:

  14. # 说明存储数据的结构还未生成,需要指明数据存储结构

  15. REQUEST_DATA[apiName]={str(caseId): {i: val}}

  16. else:

  17. #说明存储数据结构中最外层结构已存在

  18. if str(caseId) in REQUEST_DATA[apiName]:

  19. REQUEST_DATA[apiName][str(caseId)][i] = val

  20. else:

  21. # 说明内层结构不完整,需要指明完整的结构

  22. REQUEST_DATA[apiName][str(caseId)] = {i: val}

  23. else:

  24. print("请求参数中不存在字段" + i)

  25. elif key == "response":

  26. #说明需要存储的依赖数据来自接口的响应body,应该将数据存储到RESPONSE_DATA

  27. for j in value:

  28. if j in response_source:

  29. val = response_source[j]

  30. if apiName not in RESPONSE_DATA:

  31. # 说明存储数据的结构还未生成,需要指明数据存储结构

  32. RESPONSE_DATA[apiName]={str(caseId): {j: val}}

  33. else:

  34. #说明存储数据结构中最外层结构已存在

  35. if str(caseId) in RESPONSE_DATA[apiName]:

  36. RESPONSE_DATA[apiName][str(caseId)][j] = val

  37. else:

  38. # 说明内层结构不完整,需要指明完整的结构

  39. RESPONSE_DATA[apiName][str(caseId)] = {j: val}

  40. else:

  41. print("接口的响应body中不存在字段" + j)

  42. elif key == "headers":

  43. for k, v in value.items():

  44. if k == "request":

  45. # 说明需要往REQUEST_DATA变量中写入存储数据

  46. for item in v:

  47. if item in req_headers:

  48. header = req_headers[item]

  49. if "headers" in REQUEST_DATA[apiName]:

  50. REQUEST_DATA[apiName]["headers"][item] = header

  51. else:

  52. REQUEST_DATA[apiName]["headers"] = {item: header}

  53. elif k == "response":

  54. # 说明需要往RESPONSE_DATA变量中写入存储数据

  55. for it in v:

  56. if it in res_headers:

  57. header = res_headers[it]

  58. if "headers" in RESPONSE_DATA[apiName]:

  59. RESPONSE_DATA[apiName]["headers"][it] = header

  60. else:

  61. RESPONSE_DATA[apiName]["headers"] = {item: header}

  62. print(REQUEST_DATA)

  63. print(RESPONSE_DATA)

  64. if __name__ == "__main__":

  65. r = {"username": "srwcx01", "password": "wcx123wac1", "email": "wcx@qq.com"}

  66. req_h = {"cookie":"csdfw23"}

  67. res_h = {"age":597232}

  68. s = {"request": ["username", "password"], "response": ["userid"],"headers":{"request":["cookie"],

  69. "response":["age"]}}

  70. res = {"userid": 12, "code": "00"}

  71. RelyDataStore.do(s, "register", 1, r, res, req_headers=req_h, res_headers=res_h)

  72. print(REQUEST_DATA)

  73. print(RESPONSE_DATA)

6.3 校验数据结果(CheckResult.py)

  1. import re

  2. class CheckResult(object):

  3. def __init__(self):

  4. pass

  5. @classmethod

  6. def check(self, responseObj, checkPoint):

  7. responseBody = responseObj.json()

  8. # responseBody = {"code": "", "userid": 12, "id": "12"}

  9. errorKey = {}

  10. for key, value in checkPoint.items():

  11. if key in responseBody:

  12. if isinstance(value, (str, int)):

  13. # 等值校验

  14. if responseBody[key] != value:

  15. errorKey[key] = responseBody[key]

  16. elif isinstance(value, dict):

  17. sourceData = responseBody[key]

  18. if "value" in value:

  19. # 模糊匹配校验

  20. regStr = value["value"]

  21. rg = re.match(regStr, "%s" %sourceData)

  22. if not rg:

  23. errorKey[key] = sourceData

  24. elif "type" in value:

  25. # 数据类型校验

  26. typeS = value["type"]

  27. if typeS == "N":

  28. # 说明是整形校验

  29. if not isinstance(sourceData, int):

  30. errorKey[key] = sourceData

  31. else:

  32. errorKey[key] = "[%s] not exist" %key

  33. return errorKey

  34. if __name__ == "__main__":

  35. r = {"code": "00", "userid": 12, "id": 12}

  36. c = {"code": "00", "userid": {"type": "N"}, "id": {"value": "\d+"}}

  37. print(CheckResult.check(r, c))

6.4 往excel里面写结果

  1. from config.public_data import *

  2. def write_result(wbObj, sheetObj, responseData, errorKey, rowNum):

  3. try:

  4. # 写响应body

  5. wbObj.writeCell(sheetObj, content="%s" %responseData,

  6. rowNo = rowNum, colsNo=CASE_responseData)

  7. # 写校验结果状态及错误信息

  8. if errorKey:

  9. wbObj.writeCell(sheetObj, content="%s" %errorKey,

  10. rowNo=rowNum, colsNo=CASE_errorInfo)

  11. wbObj.writeCell(sheetObj, content="faild",

  12. rowNo=rowNum, colsNo=CASE_status, style="red")

  13. else:

  14. wbObj.writeCell(sheetObj, content="pass",

  15. rowNo=rowNum, colsNo=CASE_status, style="green")

  16. except Exception as err:

  17. raise err

七、创建Log目录用来存放日志
八、主函数

  1. #encoding=utf-8

  2. import requests

  3. import json

  4. from action.get_rely import GetRely

  5. from config.public_data import *

  6. from utils.ParseExcel import ParseExcel

  7. from utils.HttpClient import HttpClient

  8. from action.data_store import RelyDataStore

  9. from action.check_result import CheckResult

  10. from action.write_result import write_result

  11. from utils.Log import *

  12. def main():

  13. parseE = ParseExcel()

  14. parseE.loadWorkBook(file_path)

  15. sheetObj = parseE.getSheetByName("API")

  16. activeList = parseE.getColumn(sheetObj, API_active)

  17. for idx, cell in enumerate(activeList[1:], 2):

  18. if cell.value == "y":

  19. #需要被执行

  20. RowObj = parseE.getRow(sheetObj, idx)

  21. apiName = RowObj[API_apiName -1].value

  22. requestUrl = RowObj[API_requestUrl - 1].value

  23. requestMethod = RowObj[API_requestMothod - 1].value

  24. paramsType = RowObj[API_paramsType - 1].value

  25. apiTestCaseFileName = RowObj[API_apiTestCaseFileName - 1].value

  26. # 下一步读取用例sheet表,准备执行测试用例

  27. caseSheetObj = parseE.getSheetByName(apiTestCaseFileName)

  28. caseActiveObj = parseE.getColumn(caseSheetObj, CASE_active)

  29. for c_idx, col in enumerate(caseActiveObj[1:], 2):

  30. if col.value == "y":

  31. #需要执行的用例

  32. caseRowObj = parseE.getRow(caseSheetObj, c_idx)

  33. requestData = caseRowObj[CASE_requestData - 1].value

  34. relyData = caseRowObj[CASE_relyData - 1].value

  35. responseCode = caseRowObj[CASE_responseCode - 1].value

  36. responseData = caseRowObj[CASE_responseData - 1].value

  37. dataStore = caseRowObj[CASE_dataStore -1].value

  38. checkPoint = caseRowObj[CASE_checkPoint - 1].value

  39. #发送接口请求之前需要做一下数据依赖的处理

  40. if relyData:

  41. logging.info("处理第%s个接口的第%s条用例的数据依赖!")

  42. requestData = GetRely.get(eval(requestData), eval(relyData))

  43. httpC = HttpClient()

  44. response = httpC.request(requestMethod=requestMethod,

  45. requestData=requestData,

  46. requestUrl=requestUrl,

  47. paramsType=paramsType

  48. )

  49. # 获取到响应结果后,接下来进行数据依赖存储逻辑实现

  50. if response.status_code == 200:

  51. responseData = response.json()

  52. # 进行依赖数据存储

  53. if dataStore:

  54. RelyDataStore.do(eval(dataStore), apiName, c_idx - 1, eval(requestData), responseData)

  55. # 接下来就是校验结果

  56. else:

  57. logging.info("接口【%s】的第【%s】条用例,不需要进行依赖数据存储!" %(apiName, c_idx))

  58. if checkPoint:

  59. errorKey = CheckResult.check(response, eval(checkPoint))

  60. write_result(parseE, caseSheetObj, responseData, errorKey, c_idx)

  61. else:

  62. logging.info("接口【%s】的第【%s】条用例,执行失败,接口协议code非200!" %(apiName, c_idx))

  63. else:

  64. logging.info("第%s个接口的第%s条用例,被忽略执行!" %(idx -1, c_idx-1))

  65. else:

  66. logging.info("第%s行的接口被忽略执行!" %(idx -1))

  67. if __name__=="__main__":

  68. main()

框架待完善,请大家多多指教~
以上内容希望对你有帮助,有被帮助到的朋友欢迎点赞,评论。

 

总结:

感谢每一个认真阅读我文章的人!!!

作为一位过来人也是希望大家少走一些弯路,如果你不想再体验一次学习时找不到资料,没人解答问题,坚持几天便放弃的感受的话,在这里我给大家分享一些自动化测试的学习资源,希望能给你前进的路上带来帮助。

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

 

          视频文档获取方式:
这份文档和视频资料,对于想从事【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!以上均可以分享,点下方小卡片即可自行领取。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值