pytest封装请求类

一、解决接口关联的三种方式

接口关联:接口2的入参需要接口1的返回值

(1).将关联值保存在类变量中(不能跨文件使用)

(2).将关联值保存在extract.yaml文件中。接口1写入关联值,接口2读取关联值

(3).封装请求类,测试用例数据中写{{access_token}},封装的请求类在实际发送请求时,会将{{access_token}}替换为extract.yaml的真实值

二、接口关联---将关联值保存在extract.yaml文件

接口1:上传图片,返回图片的URL

接口2:将图片上传至相册,需要接口1的图片URL

1、创建extract.yaml文件保存关联值

2、编写工具类读写extract.yaml中的值

python 复制代码
    def read_extract_yaml(self,key):
        path="C:\\Users\\mingyuewu\\PycharmProjects\\mashang\\config\\extract.yaml"
        with open(path,mode="r",encoding="utf-8") as f:
            value = yaml.load(stream=f,Loader=FullLoader)
            #读取的value为字典格式
            return value[key]
    def write_extract_yaml(self,data):
        path="C:\\Users\\mingyuewu\\PycharmProjects\\mashang\\config\\extract.yaml"
        # data需为字典格式
        with open(path,mode="a+",encoding="utf-8") as f:
            yaml.dump(data,stream=f,allow_unicode=True)

    # 清空文件
    def clear_extract_yaml(self):
        path = "C:\\Users\\mingyuewu\\PycharmProjects\\mashang\\config\\extract.yaml"
        with open(path, mode="w", encoding="utf-8") as f:
            f.truncate()

3、接口上传图片、图片上传相册

python 复制代码
    def test_login(self):
        url= "/api/login"
        data ={
                "username": "username",
                "password": "password"
        }
        res= RequestUtil().send_request("post", url=url,  data=data)
  
    def  test_upload_photo(self):
        # ConfigYamlUtil().clear_extract_yaml()
        url="/api/admin/photos/albums/cover"
        method = "post"
        files = {
            "file": ("1.webp", open("./1.webp", "rb"), "application/octet-stream")
        }
        res = RequestUtil().send_request(method=method, url=url, files=files)
        cover_url = jsonpath.jsonpath(res.json(), '$.data')[0]
        data = {"cover_url": cover_url}
        # 将关联值写入文件
        ConfigYamlUtil().write_extract_yaml(data)

    def test_upload_ablums(self):
        url="/api/admin/photos"
        method="post"
        headers = {
            "Content-Type ": "application/json;charset=UTF-8"
        }
        #从文件读取关联值
        cover_url=ConfigYamlUtil().read_extract_yaml("cover_url")
        data = json.dumps(
            {
                "albumId": "1",
                 "photoUrlList": [cover_url]
            }
        )
        res = RequestUtil().send_request(method=method, url=url, headers=headers, data=data)
        print(res.request.body)
        print(res.request.headers)

三、封装requestUtil类解析测试数据中的关联值

1、原理

使用extract.yaml处理接口关联时,是在用例方法 中,写入/读取extract.yaml的关联值。

封装requestUtil处理接口关联时,是在requestUtil中添加方法,可以识别测试用例中的关联值。举例:上传图片到相册接口的测试数据photo_testdata.yaml文件如下:

(1)关联值cover_url用{{}}括起来,表示需要解析提取的值。

(2)requestUtil执行send_request方法时,使用参数化读取photo_testdata.yaml中的测试数据。

(3)requestUtil识别测试数据中是否有{{}}标识的变量,如果有则在extract.yaml文件种查找该变量对应的value,将{{}}标识的变量,替换为value

bash 复制代码
  data:
   albumId: 5
   photoUrlList: 
   -{{cover_url}}

2、代码

(1)、编写图片上传置接口测试数据upload_photo_album.yaml

yaml 复制代码
-
 feature: 相册管理
 story: 上传接口
 title: 上传图片到相册
 request:
  method: post
  url: /api/admin/photos
  headers:
   Content-Type: application/json;charset=UTF-8
   Accept-Encoding: gzip, deflate
   User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36
   Referer: http://114.55.135.15:81/albums/5
  data:
   albumId: 5
   photoUrlList:
    - "{{cover_url}}"
 validate: success
 

(2)编写读取测试数据的文件

python 复制代码
import yaml

class ReadTestdataYaml:
    def read_testdata(self,file_path):
        #file_path="C:\\Users\\mingyuewu\\PycharmProjects\\mashang\\testdatas\\upload_photo_ablum.yaml"
        with open(file_path,mode="r",encoding="utf-8") as f:
            value = yaml.load(f,Loader=yaml.FullLoader)
            return value

if __name__ =="__main__":
    file_path = "C:\\Users\\mingyuewu\\PycharmProjects\\mashang\\testdatas\\upload_photo_ablum.yaml"
    print(ReadTestdataYaml().read_testdata(file_path))

(3)封装RequestUtil

deal_variables方法将测试数据种{{}}标识的关联值解析为实际值

send_request种处理了url、headers、params、data、json几种传参方式值的替换

python 复制代码
import requests
import json
from tools.config_yaml_util import ConfigYamlUtil

class RequestUtil():
    # 统一会话
    session = requests.session()
    # 获取被测系统的IP地址
    base=""
    # 从配置文件中读取对应IP
    def  __init__(self):
        RequestUtil.base = ConfigYamlUtil().read_config_yaml("url","blog_url")

    def deal_variables(self,data):
        '''
        :param 待处理含{{access_token}}的数据:
        :return: 返回将{{}}中的值处理为 extract.yaml文件中对应的实际值
        '''
        #1、将数据类型全部处理为string,保存在str变量中
        if data and isinstance(data,dict):
            str = json.dumps(data)
        else:
            str = data
        # url = "http://11.11.11.11:80/index?access_token={{access_token}}&cover_url={{cover_url}}"
        # 2、将{{variable}}中的数据替换为extract.yaml中的实际值
        for i in range(1, str.count("{{") + 1): #处理字符串中含多个{{}}的情况
            if "{{" in str and "}}" in str:
                start_index = str.index("{{")
                end_index = str.index("}}")
                before_var =str[start_index:end_index + 2]
                print("\n-------------------替换前{}".format(before_var))
                after_var = ConfigYamlUtil().read_extract_yaml(key=before_var[2:-2])
                print("-------------------替换后{}".format(after_var))
                str = str.replace(before_var, after_var)
                print("-------------------最终结果{}".format(str))
        # 3、数据类型还原
        if  data and isinstance(data,dict):
            data = json.loads(str)
        else:
            data = str
        return(data)
        
    def send_request(self,method,url,**kwargs):
        #1、将method处理为小写
        self.method = str(method).lower()
        #2、处理URL 拼接完整
        self.url= RequestUtil.base+url
        #3、将url中类似{{access_token}}的变量,替换为extract.yaml文件中实际的值
        self.url = self.deal_variables(self.url)
        #4、将headers,params,json,data参数中,类似{{access_token}}的变量,替换为extract.yaml文件中实际的值
        for key,value in kwargs.items(): # data ={"username":"{{}}","password"}  headers={}
            if key in ["headers","params","data","json"]:
                kwargs[key] = self.deal_variables(value) #kwargs[key]
        #5、发送请求
        res=RequestUtil.session.request(method=self.method,url=self.url, **kwargs)
        print(res.text)
        return res

4、测试用例类

python 复制代码
 @pytest.mark.parametrize('casedata',ReadTestdataYaml().read_testdata("C:\\Users\\mingyuewu\\PycharmProjects\\mashang\\testdatas\\upload_photo_ablum.yaml"))
    def test_upload_ablums(self,casedata):
        url=casedata["request"]["url"]
        method=casedata["request"]["method"]
        headers = casedata["request"]["headers"]
        #cover_url=ConfigYamlUtil().read_extract_yaml("cover_url")
        data=casedata["request"]["data"]
        res = RequestUtil().send_request(method=method, url=url, headers=headers, data=json.dumps(data))
        print(res.request.body)
        print(res.request.headers)
相关推荐
老白干2 小时前
jjwt 0.9.1 在 JDK 11+ 上的两个“坑”与完整解决方案
java·python·log4j
笨鸟先飞,勤能补拙8 小时前
AI 赋能网络安全:技术全景、成熟度评估与实战案例
人工智能·python·安全·web安全·网络安全·sqlite·github
长和信泰光伏储能9 小时前
京津冀光伏发电:绿色能源的未来之路
python·能源
浦信仿真大讲堂9 小时前
从重复操作到自动化闭环:如何让 CST 与 Python 真正协同起来
python·自动化·cst·仿真软件·达索软件
Gu Gu Study10 小时前
ScoutLoop开放域深度研究引擎(agent的初步设计想法)
人工智能·python
卷无止境11 小时前
写代码这件事,到底该讲究点什么?
后端·python
卷无止境11 小时前
循环复杂度到底在算什么,Python 代码怎么才能写得让人一看就懂
后端·python
lpfasd12311 小时前
MediaCrawler 项目深度分析
chrome·python·chrome devtools
Dxy123931021611 小时前
Python项目打包成EXE完整教程(PyInstaller实战避坑)
开发语言·python
bamb0012 小时前
一个项目带你入门AI应用开发01
python