1. 前言 今年2月调去支持项目接口测试,测试过程中使用过postman、jmeter工具,基本能满足使用,但是部分情况下使用较为麻烦。 比如:部分字段存在唯一性校验或字段间有业务性校验,每次请求均需手工修改部分报文内容,使用工具难以满足实际使用。 因此,萌生了使用python去实现接口自动化的想法。之前未接触过接口测试,但有一点编程基础,经过2个多月的磕磕碰碰,不断完善,经历2次重构之后,最后基本达成了目标。

  2. 技术栈 python语言 requests库 unittest单元测试框架 HTMLTestReportCN、BeautifulReport测试报告

  3. 实现的功能概述 支持post、get等请求类型,xml、json格式的报文 支持使用excel编写测试用例,测试用例支持涉及多接口的场景用例;支持按脚本的形式编写测试用例 支持测试结果保存至数据库,支持生成html报告,支持将生成的测试结果导出到excel文件 支持邮件发送测试结果 支持多线程并发执行测试用例

  4. 框架及项目结构 APIS_AutoTest

api: 主程序目录

comm:公共函数,包括:接口请求基类、请求及相应数据操作基类等

intf_handle:接口操作层,包含:接口初始化、断言等

business:业务实现部分

utils:工具类,包括:读取文件、发送邮件、excel操作、数据库操作、日期时间格式化等

config:配置文件目录,包含yaml配置文件、以及路径配置

data:测试数据目录,用于存放测试数据

temp:临时文件目录,用于存放临时文件

result:结果目录

report:测试报告目录,用于存放生成的html报告

details:测试结果详情目录,用于存放生成的测试用例执行结果excel文件

log:日志文件目录

test:测试用例、测试集相关目录,启动test_suite执行用例文件存放在此

test_case:测试用例存放路径

test_suite:测试模块集,按模块组装用例

  1. 测试用例执行流程 以脚本形式编写的测试用例执行流程图:

以excel形式编写的测试用例执行流程图:

  1. 核心方法设计 接口请求基类

RequestBase(request_type, url, header, body, data_type=None)

功能描述:

根据传入的请求类型,请求地址,请求头,请求体,发送接口请求,获得响应头,响应体

request_type: 请求类型,只能是'GET', 'POST', 'HEAD', 'OPTIONS', 'PUT', 'DELETE', 'TRACE', 'CONNECT'中的一个,无大小写要求 url: 请求地址,完整的接口地址 head: 请求头 body:请求体,xml格式请求体为字符串;json格式请求体需传入json格式 data_type: 数据类型,未使用字段,备用。可为:xml、json 支持方法

__send_request() 发送请求,类私有方法,初始化时调用,调用方法返回:响应对象

get_respond() 获取响应对象,调用方法返回:响应对象

get_respond_head() 获取响应头,调用方法返回:响应头

get_respond_body() 获取响应体,调用方法返回:响应体

请求或响应数据操作基类

RequestRespondHandle(data_type, body, fields, value_dict=None)

功能描述:

根据传入的xml、json格式请求体或响应体,读取字段的值或更新字段的值

参数描述:

data_type: 数据类型,当前仅支持xml、json,不区分大小写 body: 请求体或响应体,json格式请求体支持传入字典、json格式数据(自动转换为字典) fields: 字段名称,支持多字段传入,支持数据类型:字符串、元组、列表。多字段传入形式,字符串:多个字段名称之间逗号隔开,如:'a1,b2';元组、列表正常传入即可。json格式:需写入完整节点路径,如:body.base.name,对应list类型的需传入索引位置,如:body.baselist[0].name value_dict: 字段值字典,以字段名称及字段值键值对的方式存储数据,读取字段值时,一般不需传入,也支持传入(用于读取excel形式流程前后传值);更新字段值时,需传入,且字典中的key值需要与fields中的字段名对应。 支持方法:

get_fields_value() 获取字段值,调用方法即可获取到xml或json格式的请求体或响应体对应的字段值,并返回:字段值字典

update_fields_value() 更新字段值,调用方法即可更新请求体中对应的字段值,返回更新后的请求体。 Json格式请求体返回格式为字典。

不足与改进:

xml格式,读取或更新字段时,若存在多个相同名称字段,默认只选第一个; json格式,读取嵌套列表的时候,未支持按列表读取,当前需精确位置单个读取或更新;

请求体初始化-接口映射类

RequestMsgInitMapper(data_type, intf_code, request_body, **kwargs)

功能描述:

根据传入的接口编号,映射到对应的接口请求报文的初始化方法,进行接口初始化

参数描述:

data_type: 数据类型,执行xml、json,不区分大小写 intf_code: 接口编号,每个接口都要一个接口编号,根据接口编号可以唯一确定一个接口 request_body: 请求体,json格式请求体支持传入字典、json格式数据 **kwargs: 可变关键字参数,每个接口初始化时,参数数量均不一致,所有需要使用可变参数,需要以a=value这种方式传入。部分字段(如id)可在方法内设置生成方法,一般可变参数设置都是用于前后接口字段传值。 支持方法:

start_Intf_init_mapper() 启动 接口初始化映射,该方法通过判断传入数据类型、接口编号,执行对应的接口初始化方法。 调用方法后,进行对应接口的初始化,并返回初始化后的请求体。 Json格式的数据,返回json格式的请求体(不管传入的是字典格式、还是json格式)。

适用场景说明:

接口映射类主要是针对不同接口初始化字段涉及复杂业务判断,需按接口单独编写的场景。 如果一个接口初始化涉及的字段均不涉及业务相关的复杂判断处理,可以直接统一使用通用接口初始化方法进行初始化。

通用接口初始化方法

intf_base_init(data_type, request_body, **kwargs)

功能描述:

根据可变关键字参数传入的键值对,进行接口报文初始化,返回初始化后的请求体

参数描述:

data_type: 数据类型,执行xml、json,不区分大小写 request_body: 请求体,json格式请求体支持传入字典、json格式数据 **kwargs:可变关键字参数,每个接口初始化时,参数数量均不一致,所有需要进行初始化的字段,均需以键值对的方式传入。 适用场景说明:

接口初始化字段不涉及复杂逻辑判断,直接传值后更新即可;该方式也适用于接口请求头的初始化。

  1. 数据操作类 数据操作主要是数据读取、写入,主要分为如下几类:
  • 读取txt、json等文件内容(整个读取)、写入内容到文件
  • 读取yaml文件内容
  • 读取excel表格内容、导出excel表格、读取excel并作为模板
  • 操作数据库表中的数据(增删改查)

读取txt/json文件内容,写入内容到文件

FileHandle(file_name, file_path)

功能描述:

读取文件所有内容

参数描述:

file_name:读取/写入文件名称,包含后缀,支持txt,json等 file_path:读取/写入文件所在的目录 支持方法:

read_file_content() 读取文件内容,并以字符串返回

write_to_file(content) 将内容写入文件

读取yaml文件内容

ReadYaml(file_path)

功能描述:

读取yaml文件内,支持按名称读取

参数描述:

file_path:读取文件的完整路径 支持方法:

get_yaml() 读取yaml文件所有内容,并以字典格式返回

get_value(level_name) 读取yaml文件字段的值,并返回 level_name: 节点字段名称,如涉及多节点需传入对应路径,如:db.host

读取excel表格内容、导出excel表格、读取excel并作为模板

ExcelHandle()

功能描述:

读取excel表格内容、将数据导出到excle表格中

支持方法:

read_excel_data(excel_path, sheet_name=None)

读取excel表格内容,并以列表嵌套列表的方式返回

excel_path: 读取excel文件的完整路径 sheet_name: 读取excel的页签名称,默认读取第一个页签

export_to_excel(data, head, file_name, time_flag=None)

将数据导出到excle表格中

data: 需要导出到excel的内容,元组嵌套元组(对应数据库中查询返回的结果) head: excel表头,列表、元组嵌套元组(数据库中查询表头、描述,支持多表头) file_name: excel文件名称,包含后缀.xlsx,excel导出路径系统默认 time_flag: 时间戳标记,可传入用例执行的报告号,使其对应

copy_excel_template(template_path, sheet_name=None)

复制excel表格模板,返回workbook, workssheet

template_path: 模板文件完整路径 sheet_name: 模板文件页签名称,默认第一个页签

操作数据库数据

功能描述:

表数据读取:根据情况读取所需数据,返回数据格式元组嵌套元组。 插入/更新表数据:根据实际内容,写入数据到对应的表中 备注:

数据库部分封装为数据库操作类

  1. 部分关键代码 接口请求基类

import json

import requests

class RequestBase:

def __init__(self, request_type, request_url, request_body, request_headers, intf_type=None):"""请求接口公共类:param request_type: 请求类型:post, get:param request_url: 请求url地址:param request_headers:  请求头:param request_body:  请求体(xml类型传入字符串格式,json类型数据必须传入json格式,不能传入字典):param intf_type:  接口类型:webservice, api,分别对应接口数据格式:xml, json"""self.request_type = request_typeself.request_url = request_urlself.request_body = request_bodyself.request_headers = request_headersself.intf_type = intf_typeself.res = self.__send_request()# 发送请求
def __send_request(self):if not isinstance(self.request_type, str):print('请求类型格式错误。')return Noneif self.request_type.upper() not in ['GET', 'POST', 'HEAD', 'OPTIONS', 'PUT', 'DELETE', 'TRACE', 'CONNECT']:print('请求类型不存在。')return Nonereturn requests.request(method=self.request_type, url=self.request_url, data=self.request_body.encode('utf-8'),headers=self.request_headers)# 获取响应
def get_respond(self):return self.res# 获取响应头
def get_respond_head(self):return self.res.headers# 获取响应体
def get_respond_body(self):if self.res.content:return self.res.text
复制代码

请求或响应数据操作基类

import json import re

""" 对请求体或响应体进行处理:

  1. 支持读取请求体或响应体中字段的值
  2. 支持更新请求体中字段的值 """

递归调用,更新json中的字段值

def update_json_step(node, json_str, value, i=0): # 当前节点索引(负向) node_index = -len(node) + i

# 如果包含[n]形式,说明节点为列表,需处理
if '[' in node[node_index] and ']' in node[node_index]:list_node, list_index = node[node_index].split('[')index = list_index.split(']')[0]if index is None or index == '':print('参数传入错误,请指定列表[%s]索引' % list_node)else:index = int(index)return update_json_step(node, json_str[list_node][index], value, i + 1)# 判断如果当前节点为最后一个节点,则更新value值
if node_index == -1:json_str[node[-1]] = valuereturn json_strreturn update_json_step(node, json_str[node[node_index]], value, i + 1)
复制代码

class DataHandle:

def __init__(self, data_type, data_msg, fields, value_dict=None):"""处理请求体或响应体数据,读取或更新字段值:param data_type:  数据类型:xml,json:param data_msg: 请求体或响应体:param fields: 字段值,支持多字读方式,字段间逗号隔开;或传入列表、元组json格式:需写入完整节点路径,如:body.base.name,对应list类型的需传入索引位置,如:body.baselist[0].name:param value_dict: 以字典键值对保存字段值"""self.data_type = data_typeself.data = data_msg# fields支持str,list方式,str自动转换为listif isinstance(fields, str):self.fields = fieldsself.fields_list = []if ',' in fields:self.fields_list = fields.strip().split(',')else:self.fields_list.append(fields.strip())elif isinstance(fields, list):self.fields_list = fieldselse:self.fields_list = list(fields)# 初始化字典值if value_dict is None:self.value_dict = dict()else:self.value_dict = value_dictdef get_fields_value(self):"""获取字段值1. 支持获取多个字段值,输入字符串或列表, 元组"""step_dict = self.value_dict# 字段列表循环获取for p in self.fields_list:if p == '':continue# 处理xml格式报文if self.data_type.upper() == 'XML':pattern = '<' + p + '>.*</' + p + '>'search_result = re.search(pattern, self.data)if search_result is not None:# 包括标签和值都匹配上field_and_value = search_result.group()# 去除标签获取字段值,并存入字典step_dict[p] = (field_and_value.split('</')[0]).split('>')[-1]else:# print('参数[%s]提取失败,无匹配值。' % p)pass# 处理json格式报文elif self.data_type.upper() == 'JSON':# 获取层级(使用.隔开)node = p.split('.')# json转换字典if isinstance(self.data, dict):temp = self.dataelse:temp = json.loads(self.data)# 逐层读取数据for per_node in node:if '[' in per_node and ']' in per_node:per_node, index_str = per_node.split('[')index = int(index_str.split(']')[0])temp = temp.get(per_node)[index]if temp is None:breakelse:temp = temp.get(per_node)if temp is None:break# 讲读取的结果写入字典step_dict[p] = temp# 非 xml,json的数据格式,报错退出else:print('ERROR: 不支持此数据类型[%s]' % self.data_type)breakreturn step_dictdef update_fields_value(self):"""更新字段值支持更新单个字段值,多个字段值(字段名 字符串或列表、元组,字段值 字典)"""req_body = self.data# 字段列表循环更新for p in self.fields_list:# 入参类型判断if isinstance(self.value_dict, dict):# 参数在字典中不存在,则跳过if p not in self.value_dict.keys():print('ERROR: 字典中不存在参数[%s]。' % p)continue# 获取字典中参数的值value = self.value_dict[p]elif isinstance(self.value_dict, str):value = self.value_dictelse:print('函数入参[%s]类型不支持,请传入字符串或字典。' % self.value_dict)break# 更新数据类型为 xml 的参数值if self.data_type.upper() == 'XML':# 优先寻找是否存在指定更新参数,若有,则按指定参数更新if '${' + p + '}' in req_body:req_body = req_body.replace('${' + p + '}', value)# 其次寻找标签参数值,若有,则按标签更新值else:# 检查标签是否存在,若存在if '<' + p + '>' in req_body and '</' + p + '>' in req_body:# 正则匹配pattern = '<' + p + '>.*</' + p + '>'new_field_and_value = '<' + p + '>' + str(value) + '</' + p + '>'search_result = re.search(pattern, req_body)# 若正则匹配结果存在,则进行字段值更新if search_result is not None:old_field_and_value = search_result.group()req_body = req_body.replace(old_field_and_value, new_field_and_value)else:print('参数[%s]匹配标签失败,请检查报文中标签格式。' % p)else:# print('参数[%s]匹配标签失败,无此标签。' % p)continue# 更新数据类型为 xml 的参数值elif self.data_type.upper() == 'JSON':# json转换字典if isinstance(self.data, dict):req_body = self.dataelse:req_body = json.loads(self.data)# 获取层级node = p.split('.')# 调用递归函数更新字段值update_json_step(node, req_body, value)# 非 xml,json的数据格式,报错退出else:print('ERROR: 不支持此数据类型[%s]' % self.data_type)breakreturn req_body
复制代码

接口初始化通用类

from api.comm.data_handle import DataHandle

def intf_base_init(data_type, request_body, **kwargs): """ 接口初始化通用类 :param data_type: 数据类型,如:xml,json :param request_body: 请求体 :param kwargs: 可变关键字参数 :return: 请求体 """ return DataHandle(data_type, request_body, kwargs.keys(), kwargs).update_fields_value()

如果你处于想学Python自动化或者正在学习Python自动化,Python自动化的教程不少了吧,但是是最新的吗?
复制代码

可以戳戳下面的gzh【清零0】

浅谈python+requests实现接口自动化相关推荐

  1. 学习之浅谈python如何做接口自动化

    目录 前言 一.接口 二.API自动化测试(接口测试): 三.requests框架 四.自动化测试框架------->自动化测试核心技能 1. 1 接口测试类型 1.2 如何开展接口测试 1.3 ...

  2. 浅谈Python+requests+pytest接口自动化测试框架的搭建

    框架的设计思路 首先要明确进行接口自动化需要的步骤,如下图所示: 然后逐步拆解需要完成的工作: 1)了解分析需求:了解接口要实现的功能 2)数据准备:根据开发文档确定接口的基本情况,知晓接口的url. ...

  3. python+requests+pytest 接口自动化框架(四)

    目录 一.requests库简介 二.requests库常用方法 三.request()返回的response对象 四.实战案例 post(url, data=None, json=None, **k ...

  4. python+requests+pytest 接口自动化框架(一)

    目录 一.Pytest详解以及常用的插件安装 二.Pytest默认的测试用例的规则 三.Pytest用例运行方式以及参数 1.命令行模式运行 命令:pytes 2.主函数模式运行 3.基于pytest ...

  5. 浅谈python+requests接口自动化框架

    为什么要做接口自动化框架 1.业务与配置的分离 2.数据与程序的分离:数据的变更不影响程序 3.有日志功能,实现无人值守 4.自动发送测试报告 5.不懂编程的测试人员也可以进行测试 正常接口测试的流程 ...

  6. Python+Requests实现接口自动化

    一般对于自动化的理解,有两种方式的自动化. 第一,不需要写代码,完全由工具实现,这种方式的工具一般是公司自己研发的,方便黑盒测试人员使用.这种工具的特点是学习成本低,方便使用,但是通用性不强,也就是换 ...

  7. python+requests+pytest 接口自动化框架(八)

    今日内容:接口自动化测试框架封装之数据类型处理以及DDT数据驱动封装 一.数据类型处理 "${read_extract_data(tag_id)}" 替换成 110 json: { ...

  8. python如何导入requests模块_浅谈python中requests模块导入的问题

    浅谈python中requests模块导入的问题 今天使用Pycharm来抓取网页图片时候,要导入requests模块,但是在pycharm中import requests 时候报错. 原因: pyt ...

  9. 浅谈 Python 程序和 C 程序的整合

    浅谈 Python 程序和 C 程序的整合 Python 是一种用于快速开发软件的编程语言,它的语法比较简单,易于掌握,但存在执行速度慢的问题,并且在处理某些问题时存在不足,如对计算机硬件系统的访问, ...

最新文章

  1. ArcEngine的ToolbarControl解析
  2. 利用gearman实现redis缓存mysql
  3. swift4 linux,Swift 4正式发布,新功能概览
  4. 1_CUDA编程介绍(20181121)
  5. 园友们注意:淘宝网上QQ会员 4钻 3元 等都为骗子行为
  6. c#开发windows应用程序几个小技巧
  7. linux perl模块检测,Linux有问必答:如何用Perl检测Linux的发行版本
  8. 滤波电容的选择(调试中)
  9. UVa 11889 (GCD) Benefit
  10. tensorflow学习之常用函数总结:tensorflow.placeholder()函数
  11. mysql57介绍_MySQL5.7 JSON类型使用介绍
  12. JSESSIONID是什么
  13. LeetCode刷题-四因数
  14. 细胞自动机_细胞自动机和音乐
  15. 文明与征服汉尼拔阵容技能推荐
  16. TaintDroid剖析之DVM变量级污点跟踪(下篇)
  17. Google Guava 工具类库
  18. C51串口通信(张毅刚)例8-1程序解释
  19. 静态成员与非静态成员的区别
  20. RabbitMQ:Consumers的介绍和使用

热门文章

  1. db9针232接口波特率标准_RS232和RS485与RS422接口的基础知识详细介绍
  2. pandas使用set_table_attributes函数、display_html函数等在jupyter notebook中并排显示两个dataframe的内容(side by side)
  3. R语言使用ggplot2包使用geom_boxplot函数绘制基础分组箱图(不同分组配置不同的箱体填充色+灰度尺度图)实战
  4. R语言使用ggpubr包的ggarrange函数组合多张结论图(垂直组合+水平组合)并对图像进行顺序编码A、B、C,,,
  5. R语言ggplot2可视化:为箱图的均值进行连线、将多个分组的均值连接起来Joining means on a boxplot with a line
  6. sklearn RandomForest(随机森林)模型使用RandomSearchCV获取最优参数及模型效能可视化
  7. R绘制堆叠的密度图(Stacked Area Chart)
  8. 电力竞价(广东规则)详解与代码
  9. 赵方庆 北京生科院Computational strategies in exploring circular RNAs 探索环状rna的计算策略
  10. 机器学习 阴性集的选择 —— drug-target interactions (DTIs)