《接口自动化测试框架》代码片段 - 接口请求封装

抛砖引玉

requests模块是Python中发送HTTP请求的强大工具,它以其直观易用的API和人性化的设计赢得了广泛赞誉。 这个模块不仅提供了丰富的功能来定制HTTP请求,如设置请求头、传递URL参数等,还能够自动处理许多底层细节,如Cookie管理和会话保持,极大地简化了网络编程的复杂性。

在Python的网络编程中,requests模块凭借其高效且简洁的特性,成为了开发者处理网络请求的优选库; 无论是用于爬虫项目抓取网页数据,还是进行数据分析时从远程服务器获取数据,亦或是构建接口自动化测试框架,requests都能够轻松胜任。

在之前的文章中已经对requests模块的功能和用法进行了详细的介绍,不在重复。

本次将为大家展示一个实用的工具类,这个工具类是我们《接口自动化框架(付费)》中的一部分,它专门设计用于接口自动化测试 - 接口请求的相关功能。

通过这个工具类,可以更加高效地驱动测试数据进行接口测试,并与其他模块配合实现Allure报告记录。希望这个工具类能够为你的工作带来便利,并提升接口自动化测试的效率。

历史文章:Python 爬虫与接口自动化必备requests模块

历史文章:Allure速查表(03)报告结构详解和常用装饰器

历史文章:Allure速查表(04)静态和动态生成报告标记

框架文章:完美落地的自动化测试框架:智能生成?业务依赖?动态替换?报告构建?你来,这儿有!

注意:框架暂不开源,66R包执行,可免费讲解。

请添加图片描述


代码封装

# -*- coding: utf-8 -*-
"""
@Author  : yangkai
@Email   : 807440781@qq.com
@Project : KKNOBUG-API
@Module  : RequestUtils.py
@DateTime: 2024/5/09 20:28
"""
import json as js
import typingimport requests
from requests import exceptions
import allurefrom services.ResponseModel import ResponseCodeError, ResponseOtherError
from services.ExtendedDecorator import request_decorator, execution_durationclass RequestUtils(object):"""代码设计思想:1.利用requests模块构建HTTP请求客户端2.利用魔术方法____new__完成单例模式,保证HTTP请求客户端不会重复实例化3.实例化时可以配置接口请求超时时间,默认120秒4.处理请求头部信息,如未上送则附带常用属性,若以上送则与常用属性合并5.处理请求参数类型和请求参数双向绑定(request分params、data和json方式传递参数)6.处理HTTP常用请求发送(GET, POST, PUT, DELETE, HEAD, OPTIONS, CONNECT, TRACE...)7.处理响应对象中常用的信息封装成字典(url, headers, method, time, cookie, params_type, params_data...)8.处理allure报告step展示接口的请求和响应过程""""用于存储该类的当一实例"__instance = None"重写父类的__new__方法,实现单例模式"def __new__(cls, *args, **kwargs) -> object:if not cls.__instance:cls.__instance = super().__new__(cls)return cls.__instancedef __init__(self, timeout: int = 120) -> None:"""客户端发起请求前的配置"""self.TIMEOUT = timeoutself.session = requests.session()@execution_duration(number=5)def request(self, *, url: str, method: str,params: typing.Optional[str] = None,data: typing.Optional[typing.Dict[str, str]] = None,json: typing.Optional[typing.Union[typing.Dict[str, str], str]] = None,headers: typing.Optional[typing.Union[typing.Dict[str, str], str]] = None,**kwargs) -> typing.Dict[str, str]:"""按照method请求方式向url地址携带params/data/json/..数据发送HTTP请求:param url:     必填项,字符类型,接口请求地址;如:http://127.0.0.1/test:param method:  必填项,字符类型,接口请求方式;如:GET、POST、PUT、DELETE等:param params:  非必填,字符类型,接口请求参数类型(参数增加到url中):param data:    非必填,字典类型,接口请求参数类型(作为Request的内容):param json:    非必填,JSON类型,接口请求参数类型(作为Request的内容):param headers: 非必填,字典类型,接口请求的头部信息;:param kwargs:  非必填,字典类型,其他参数;:return:        返回requests请求对象"""# 1.GET:获取实体数据# 2.HEAD:获取响应头# 3.POST:提交数据# 4.PUT:上传数据# 5.PATCH:同PUT请求,对已知资源进行局部更新# 6.DELETE:删除数据# 7.OPTIONS:测试通信# 8.CONNECT:更改连接模式为管道方式的代理服务器# 9.TRACE:回显服务方收到的请求,用于测试和诊断# 1.检查请求方式是否允许methods = ('GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'CONNECT', 'TRACE')if method.upper() not in methods:raise exceptions.HTTPError(f'不支持[{method}]请求方式,支持的请求方式有:{methods}')# 2.检查是否指定请求头信息headers = RequestUtils.headers_wrapper(headers=headers, params=params, data=data, json=json)# 3.发起请求try:response = requests.request(url=url,method=method,params=params,data=data,json=json,headers=headers,timeout=int(self.TIMEOUT),**kwargs)if response.status_code != 200:raise ResponseCodeError(message="请求失败,服务器响应状态码非200",status_code=response.status_code,reason=response.reason)except exceptions.Timeout as e:raise ResponseOtherError(message="请求失败,服务器响应超时",reason=e)except exceptions.InvalidURL as e:raise ResponseOtherError(message="请求失败,URL解析失败或无效",reason=e)except exceptions.HTTPError as e:raise ResponseOtherError(message="请求失败,服务器响应异常",reason=e)except exceptions.ConnectionError as e:raise ResponseOtherError(message="请求失败,网络连接失败或服务器拒绝连接",reason=e)params_type = "json" if json is not None else "data" if data is not None else "params"params_data = json if json is not None else data if data is not None else paramsresponse_dict: dict = RequestUtils.response_wrapper(response)self.api_allure_step(url=url,headers=headers,method=method,params_type=params_type,params_data=params_data,response=response_dict,)return response_dict@staticmethoddef response_wrapper(response) -> typing.Dict[str, str]:"""将接口响应对象中常用的信息封装成字典, url, headers, method, params_type, params_data:param response: 响应对象:return: 字典"""response_dict = {}response_dict.setdefault("response_url", response.url)response_dict.setdefault("response_code", response.status_code)response_dict.setdefault("response_info", response.reason)response_dict.setdefault("response_encoding", response.encoding)response_dict.setdefault("response_text", response.text)response_dict.setdefault("response_time", response.elapsed.total_seconds())response_dict.setdefault("response_microseconds", response.elapsed.microseconds)response_dict.setdefault("response_millisecond", response.elapsed.microseconds / 1000)response_dict.setdefault("response_headers", dict(response.headers))response_dict.setdefault("response_cookie", dict(response.cookies))response_dict.setdefault("response_other", response)try:# js.dumps(response.json(), ensure_ascii=False, separators=(",", ":"))response_dict.setdefault("response_json", response.json())except Exception as e:response_dict.setdefault("response_json", e)return response_dict@staticmethoddef headers_wrapper(headers: typing.Optional[typing.Union[typing.Dict[str, str], str]] = None,params: typing.Optional[str] = None,data: typing.Optional[typing.Dict[str, str]] = None,json: typing.Optional[typing.Union[typing.Dict[str, str], str]] = None) -> typing.Dict[str, str]:"""处理请求头信息:param headers::param params::param data::param json::return:"""# 如果headers类型不符则抛出异常if not isinstance(headers, (type(None), dict, str)):raise TypeError(f"参数headers应为None、字符串、字典类型,但得到了:「{type(headers)}」类型")final_headers: dict = {"Accept-Language": "zh-CN,zh;q=0.9","Connection": "keep-alive","User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36","Accept": "application/json, text/plain, */*","Accept-Encoding": "gzip, deflate, br",}# 如果传递的headers不空且是字符串类型,则尝试加载成字典类型if headers and isinstance(headers, str):try:headers_to_dict = js.loads(headers)if isinstance(headers_to_dict, dict):final_headers.update(headers_to_dict)else:raise TypeError("字符串异常,无法转化字典类型")except js.decoder.JSONDecodeError:raise TypeError("字符串异常,无法转化字典类型")# 根据参数类型设置请求头的客户端数据类型if params or data:# 将数据编码为键值对final_headers.update({"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"})elif json:# 将数据编码为JSON对象# 可以忽略,因为使用json参数时,不需要手动序列化数据或设置Content-Type头,requests会自动处理。final_headers.update({"Content-Type": "application/json;charset=utf-8"})return final_headers@staticmethoddef datagram_wrapper(params_type: typing.Literal["params", "PARAMS", "data", "DATA", "json", "JSON"] = None,params_data: typing.Any = None,):if params_type:return {params_type.lower(): params_data}return {"json": None, "data": None, "params": None}@classmethod@request_decorator(switch=True)def api_allure_step(cls, *, url, headers, method, params_type, params_data, response):with allure.step("核心步骤一:接口请求"):allure.attach(name="请求地址", body=str(url))allure.attach(name="请求头部",body=js.dumps(headers, ensure_ascii=False, indent=4),attachment_type=allure.attachment_type.JSON)allure.attach(name="请求方式", body=str(method))allure.attach(name="请求参数类型", body=str(params_type))try:allure.attach(name="请求参数内容",body=js.dumps(params_data, ensure_ascii=False, indent=4),attachment_type=allure.attachment_type.JSON)except Exception:allure.attach(name="请求参数内容", body=str(params_data))with allure.step("核心步骤二:接口响应"):del response["response_other"]allure.attach(name="响应代码", body=str(response.get("response_code")))allure.attach(name="响应文本", body=str(response.get("response_text")))try:allure.attach(name="响应内容",body=js.dumps(response.get("response_json"), ensure_ascii=False, indent=4),attachment_type=allure.attachment_type.JSON)except Exception:allure.attach(name="响应内容", body=str(response.get("response_json")))allure.attach(name="响应耗时", body=str(response.get("response_time")) + "秒")allure.attach(name="响应对象",body=js.dumps(response, ensure_ascii=False, indent=4),attachment_type=allure.attachment_type.JSON)if __name__ == '__main__':# 测试单例模式cls1 = RequestUtils()cls2 = RequestUtils()print(cls1 is cls2)# 测试接口test_get = cls2.request(url="https://httpbin.org/get", method="GET")print(test_get)print(test_get.get("response_url"))  # http://httpbin.org/getprint(test_get.get("response_encoding"))  # utf-8print(test_get.get("response_info"))  # OKprint(test_get.get("response_code"))  # 200print(test_get.get("response_time"))  # 0.781666headers = {"Content-Type": "1111"}data = {"name": "张三", "age": 20, "phone": "10086", "address": "上海市浦东新区"}test_post = cls2.request(url="http://httpbin.org/post", method="POST", json=data, headers=headers)print(test_post)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/24104.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

重庆公司记账代理,打造专业财务管理解决方案的领先企业

重庆公司记账代理,作为专业的财务管理服务提供商,我们的目标是为公司的经营管理和决策提供科学、准确的财务数据支持,我们通过长期的专业经验和对市场的深入理解,为您提供一站式的记账服务和财务咨询。 专业团队 我们拥有一支由经…

如何移动 hiberfil.sys 文件来减少C盘空间

如何移动 hiberfil.sys 文件来减少C盘空间 hiberfil.sys 文件是什么? hiberfil.sys 文件是 Windows 系统在开启休眠功能后自动生成的内存镜像文件。这个文件保存了系统休眠时的内存内容,以便我们唤醒电脑之后可以快速恢复到休眠前的状态。这个文件通常…

基于JSP技术的师生交流平台

你好呀,我是计算机学长猫哥!如果有相关需求,文末可以找到我的联系方式。 开发语言:Java 数据库:MySQL 技术:JSP技术 工具:Myeclipse、B/S架构 系统展示 首页 管理员登录界面 学生信息管理…

Qwen2开源发布,各方位全面升级!

今天,通义千问团队带来了Qwen2系列模型,Qwen2系列模型是Qwen1.5系列模型的重大升级。包括了: 5个尺⼨的预训练和指令微调模型, 包括Qwen2-0.5B、Qwen2-1.5B、Qwen2-7B、Qwen2-57B-A14B以及Qwen2-72B; 在中⽂英语的基础上&#xf…

Thermal-BST自动化工具在Flotherm建模中的应用与优势

引言 随着科技的不断发展,电子领域的需求也越来越广泛和多样化。然而,PCB板及其上的器件建模问题一直是电子工程师在设计过程中面临的重要挑战之一。软件中原有的PCB建模工具,转换出来的模型复杂,影响后期的网格划分,…

选择云桌面必看:影响云桌面性能的一些重要因素

当云桌面发展的如火如荼并被越来越多的人所追捧的时候,偶然在网上看到有人评论说云桌面太坑,说好的免维护和节省成本好像与想象中的还是不一样。云桌面真的太坑?那是因为你没做好这几点。 选择云桌面你该关注哪些指标? 其实从云…

查询SQL03:大的国家

问题描述 如果一个国家满足下述两个条件之一,则认为该国是 大国 : 面积至少为 300 万平方公里(即,3000000 km2),或者 人口至少为 2500 万(即 25000000) 编写解决方案找出 大国 的国…

亚马逊测评自养号技术全攻略:一站式解决方案

在跨境电商这行,产品测评可是个大问题。如果你的商品销量少,评价也不多,那买家就很难注意到你的产品,更别提下单购买了。毕竟,大家都喜欢跟风买那些已经有很多人好评的产品,而不是冒险尝试一个全新的。 我们…

替代UCC28250抗干扰支持预偏置启动|支持半桥全桥|增强型驱动器

1. 产品特性(替代UCC28250) ➢ 支持预偏置启动 ➢ 死区时间可调的同步整流输出 ➢ 支持电压模控制和电流模控制 ➢ 支持源边控制和副边控制 ➢ 5V,精度3%电压输出 ➢ 软启动和打嗝恢复时间可调 ➢ 同步整流软启动阈值和时间可调 ➢ 斜坡补偿信号斜率可调 ➢…

2009年408真题解析

2009年408真题解析 【2009.1】为解决计算机主机与打印机之间速度不匹配问题,通常设置一个打印数据缓冲区,主机将要输出的数据依次写入该缓冲区,而打印机则依次从该缓冲区中取出数据。该缓冲区的逻辑结构应该是。 A.栈 B.队列 C.树 D.图 …

【单调栈讲解】

单调栈 考察单调栈。 我们需要维护一个递增的单调栈,同时要给下标入栈,而不是元素入栈。 给i位置入栈的时候,发现右指针i1位置元素一定小,而左指针i-1位置元素也一定小,所以当前i位置元素出栈对应的答案为&#xff0…

干货分享:如何做好采购和供应链管理工作?

简单来说,采购是企业获取所需货物和材料的过程,而供应链管理是将这些货物转化为产品并尽可能高效地分发给客户。 但做好采购和供应链管理的关键是实现采购和供应商的协同管理。为什么这么说呢? 在成本方面,采供协同管理使得企业…

[Vue3:Vite构建项目]:安装router实现登录页面路由跳转

文章目录 一:前置依赖查看依赖安装vite npm create vitelatest sys-instruction-0607 --template vue-ts安装路由:npm install vue-router4安装elementUI:npm install element-plus --save 二:配置文件:views&#xff…

hot100_62不同路径

不同路径 题目思路、代码1.排列组合2.动态规划 题目 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” &#xff0…

YOLOv5改进 | 注意力机制 | 在主干网络中添加SOCA模块【原理+附完整代码】

💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡 现有的基于CNN的SISR方法主要关注更宽或更深的架构设计,忽视了探索中间层的特征相关性,因此阻碍了CNN的表达能力。为…

nginx c++模块编译

不论是c还是c,nginx的第三方模块编写没什么太区别,但是提供给nginx调用的,必须是纯c的接口。 先说下为什么不能使用c编译nginx,nginx是纯c写的,而且c是兼容c的,但是用c(g)编译nginx的框架,就会出…

VRRP----虚拟路由器冗余协议(技术专题)

目录 一、VRRP的基本原理 1.1 技术背景 1.2 VRRP带来了什么 1.2.1 VRRP的作用 1.2.2 VRRP工作的过程 1.2.3 VRRP报文: 1.3 VRRP术语 1.3.1 虚拟IP地址、MAC地址 1.3.2 Master、Backup路由器 二、VRRP的基础配置 实例一 需求 配置 一、VRRP的基本原理 1.1 技术背景…

docker 拉取镜像报错: error pulling image configuration:(kafka)

一、问题描述 docker 拉取镜像报错: error pulling image configuration:(kafka) ERROR: error pulling image configuration: Get https://production.cloudflare.docker.com/registry-v2/docker/registry/v2/blobs/sha256/a6/a692873757c06a38279b61…

idea debug时提示”Method breakpoints may dramatically slow down debugging“的解决办法

问题现象 今天同事喊我过去看一个问题,项目正常启动的时候没问题,debug模式就卡住了,很久不动。我推测是哪个断点导致的,一看断点果然有情况。在方法上打了断点。 解决方式(Android Studio一样的解决) 1、View Brea…

视频大模型 Vidu 支持音视频合成;字节跳动推出语音生成模型 Seed-TTS 丨 RTE 开发者日报 Vol.221

开发者朋友们大家好: 这里是 「RTE 开发者日报」 ,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE(Real-Time Engagement) 领域内「有话题的新闻」、「有态度的观点」、「有意思的数据」、「有思考的文章」、「…