【python做接口测试的学习记录day8——pytest自动化测试框架之热加载和断言封装】

2023-11-01

一、热加载:

就是在代码执行过程当中动态的调用Python中的方法达到或得动态参数的目的

在根目录下创建debug_talk.py,这里我们写入了获得随机数的方法,后面使用值直接调用即可

import random
import time
from common.yaml_util import YamlUtil

class DebugTalk:

    #获得随机数
    def get_randon_number(self,min,max):
        return random.randint(int(min),int(max))

    #读取extract.yaml文件中的值
    def read_extract_data(self,key):
        return YamlUtil().read_yaml(key)

另外根目录创建test.py,这个是获取随机时间和本地时间的一个方法,因为我后面的接口输入数据中包含一个参数是时间

import random
import time
from common.yaml_util import YamlUtil


class Test:
    #获取随机时间
    def get_random_time(self):
        # return str(int(time.time()))[1:6]     #获取随机时间,得到的是时间戳
        return time.strftime('%H:%M:%S', time.localtime(time.time()))  #获取本地时间,并将格式转换成时分秒

    #读取extract.yaml文件中的值
    def read_extract_data(self,key):
        return YamlUtil().read_yaml(key)

接下来就是request.py文件的修改:

import jsonpath
import requests
import json
from common.yaml_util import YamlUtil
from builtins import str
import re
from debug_talk import DebugTalk
from test import  Test


class RequestUtil:

    def __init__(self,two_node,obj):
        self.base_url=YamlUtil().read_config('base',two_node)
        self.obj=obj


    #替换值的方法
    # #(替换url,params,data,json,headers)
    # #(string,int,float,list,dict)
    def replace_value(self, data):
        if data:
            # 保存数据类型
            data_type = type(data)
            # 判断数据类型转换成str
            if isinstance(data, dict) or isinstance(data, list):
                str_data = json.dumps(data)
            else:
                str_data = str(data)
            for cs in range(1, str_data.count('${') + 1):
                # 替换
                if "${" in str_data and "}" in str_data:
                    start_index = str_data.index("${")
                    end_index = str_data.index("}", start_index)
                    old_value = str_data[start_index:end_index + 1]
                    print("old_value:"+old_value)
                    #反射:通过类的对象和方法字符串调用方法
                    func_name=old_value[2:old_value.index('(')]
                    args_value1=old_value[old_value.index('(')+1:old_value.index(')')]
                    new_value=""
                    if args_value1 !="" :
                        args_value2 = args_value1.split(',')
                        new_value=getattr(self.obj,func_name)(*args_value2)
                    else:
                        new_value = getattr(self.obj, func_name)()
                    str_data = str_data.replace(old_value, str(new_value))
            # 还原数据类型
            if isinstance(data, dict) or isinstance(data, list):
                data = json.loads(str_data)
            else:
                data = data_type(str_data)
        return data


    #规范yaml测试用例
    def standard_yaml(self,caseinfo):
        caseinfo_keys= caseinfo.keys()
        #判断一级关键字是否包含:name,request,validate
        if "name" in caseinfo_keys and "request" in caseinfo_keys and "validate" in caseinfo_keys:
            #判断request下面是否包含:method、url
            request_keys=caseinfo["request"].keys()
            if "method" in  request_keys and "url" in request_keys:
                print("yaml基本架构检查通过")
                method = caseinfo['request'].pop("method") #pop() 函数用于移除列表中的一个元素,并且返回该元素的值。
                url= caseinfo['request'].pop("url")
                res = self.send_request(method,url,**caseinfo['request']) #caseinfo需要解包加**
                return_text=res.text
                return_code = res.status_code
                return_json=""
                try:
                    return_json = res.json()
                except Exception as e:
                    print("extract返回的结果不是JSON格式")

                # 提取值并写入extract.yaml文件
                if "extract" in caseinfo.keys():
                    for key, value in caseinfo["extract"].items():
                        if "(.*?)" in value or "(.+?)" in value:  # 正则表达式
                            zz_value = re.search(value, return_text)
                            if zz_value:
                                extract_value = {key: zz_value.group(1)}
                                YamlUtil().write_yaml(extract_value)
                        else:  # jsonpath
                            js_value = jsonpath.jsonpath(return_json, value)
                            if js_value:
                                extract_value = {key: js_value[0]}
                                YamlUtil().write_yaml(extract_value)
            else:
                print("在request下必须包含method,url")
        else:
            print("一级关键字必须包含name,request,validate")



    sess= requests.session()

    # 统一请求封装

    def send_request(self,method,url,**kwargs):
        method=str(method).lower()  #转换小写
        #基础路径的拼接和替换
        url= self.base_url + self.replace_value(url)
        print(url)
        #参数替换
        for key,value in kwargs.items():
            if key in ['params','data','json','headers']:
                kwargs[key]=self.replace_value(value)
            elif key == "files":
                for file_key, file_path in value.items():
                    value[file_key] = open(file_path, 'rb')
        res = RequestUtil.sess.request(method, url, **kwargs)
        print(res.text)
        return res

参数为本地时间的yaml用例文件:

-
  name: 获取城市列表
  request:
    method: post
    url: /jlcloud/simulation/${read_extract_data(data)}/ranAsPlan
    json: {"time": "${get_random_time()}"}
    headers:
      'Content-Type': 'application/json'
      'X-Token': ${read_extract_data(token)}
  validate: None

这里仅使用了随机时间,如果接口包含随机数,可类比随机时间的方法

 最后需要在用例上需要创建初始化对象,用到哪个就写哪个,我这里只用到了Test()

import requests
import json
from common.request_util import RequestUtil
from common.yaml_util import YamlUtil
from test import Test

class TestRequest:
    pass
    @pytest.mark.parametrize("caseinfo",YamlUtil().read_testcase('get_token.yaml'))
    def test_login(self,caseinfo):
        res = RequestUtil("base_test_url",Test()).standard_yaml(caseinfo)

    #
    @pytest.mark.parametrize("caseinfo", YamlUtil().read_testcase('userinfo.yaml'))
    def test_userinfo(self, caseinfo):
        res = RequestUtil("base_test_url",Test()).standard_yaml(caseinfo)
    #     print(res.text)
    #
    @pytest.mark.parametrize("caseinfo", YamlUtil().read_testcase('city_type.yaml'))
    def test_city(self, caseinfo):
        res = RequestUtil("base_test_url",Test()).standard_yaml(caseinfo)

    @pytest.mark.parametrize("caseinfo", YamlUtil().read_testcase('simulation.yaml'))
    def test_simulation(self, caseinfo):
        res = RequestUtil("base_test_url",Test()).standard_yaml(caseinfo)

    @pytest.mark.parametrize("caseinfo", YamlUtil().read_testcase('ranAsPlan.yaml'))
    def test_ranAsPlan(self, caseinfo):
        res = RequestUtil("base_test_url",Test()).standard_yaml(caseinfo)

二、断言

断言一般有两种,一种是通过返回值的状态码是否等于200,一种是业务的判断,业务判断可以使用两种方式,一种是想等,一种是包含

1、状态断言:返回的状态码是否等于200

2、业务断言:相等的断言、包含的断言

在request.py中进行断言方法的封装:

import jsonpath
import requests
import json
from common.yaml_util import YamlUtil
from builtins import str
import re
from debug_talk import DebugTalk
from test import  Test


class RequestUtil:

    def __init__(self,two_node,obj):
        self.base_url=YamlUtil().read_config('base',two_node)
        self.obj=obj


    #替换值的方法
    # #(替换url,params,data,json,headers)
    # #(string,int,float,list,dict)
    def replace_value(self, data):
        if data:
            # 保存数据类型
            data_type = type(data)
            # 判断数据类型转换成str
            if isinstance(data, dict) or isinstance(data, list):
                str_data = json.dumps(data)
            else:
                str_data = str(data)
            for cs in range(1, str_data.count('${') + 1):
                # 替换
                if "${" in str_data and "}" in str_data:
                    start_index = str_data.index("${")
                    end_index = str_data.index("}", start_index)
                    old_value = str_data[start_index:end_index + 1]
                    print("old_value:"+old_value)
                    #反射:通过类的对象和方法字符串调用方法
                    func_name=old_value[2:old_value.index('(')]
                    args_value1=old_value[old_value.index('(')+1:old_value.index(')')]
                    new_value=""
                    if args_value1 !="" :
                        args_value2 = args_value1.split(',')
                        new_value=getattr(self.obj,func_name)(*args_value2)
                    else:
                        new_value = getattr(self.obj, func_name)()
                    str_data = str_data.replace(old_value, str(new_value))
            # 还原数据类型
            if isinstance(data, dict) or isinstance(data, list):
                data = json.loads(str_data)
            else:
                data = data_type(str_data)
        return data


    #规范yaml测试用例
    def standard_yaml(self,caseinfo):
        caseinfo_keys= caseinfo.keys()
        #判断一级关键字是否包含:name,request,validate
        if "name" in caseinfo_keys and "request" in caseinfo_keys and "validate" in caseinfo_keys:
            #判断request下面是否包含:method、url
            request_keys=caseinfo["request"].keys()
            if "method" in  request_keys and "url" in request_keys:
                print("yaml基本架构检查通过")
                method = caseinfo['request'].pop("method") #pop() 函数用于移除列表中的一个元素,并且返回该元素的值。
                url= caseinfo['request'].pop("url")
                res = self.send_request(method,url,**caseinfo['request']) #caseinfo需要解包加**
                return_text=res.text
                return_code = res.status_code
                return_json=""
                try:
                    return_json = res.json()
                except Exception as e:
                    print("extract返回的结果不是JSON格式")

                # 提取值并写入extract.yaml文件
                if "extract" in caseinfo.keys():
                    for key, value in caseinfo["extract"].items():
                        if "(.*?)" in value or "(.+?)" in value:  # 正则表达式
                            zz_value = re.search(value, return_text)
                            if zz_value:
                                extract_value = {key: zz_value.group(1)}
                                YamlUtil().write_yaml(extract_value)
                        else:  # jsonpath
                            js_value = jsonpath.jsonpath(return_json, value)
                            if js_value:
                                extract_value = {key: js_value[0]}
                                YamlUtil().write_yaml(extract_value)
                #断言:
                self.assert_result(caseinfo['validate'],return_json,return_code)
            else:
                print("在request下必须包含method,url")
        else:
            print("一级关键字必须包含name,request,validate")



    sess= requests.session()

    # 统一请求封装

    def send_request(self,method,url,**kwargs):
        method=str(method).lower()  #转换小写
        #基础路径的拼接和替换
        url= self.base_url + self.replace_value(url)
        print(url)
        #参数替换
        for key,value in kwargs.items():
            if key in ['params','data','json','headers']:
                kwargs[key]=self.replace_value(value)
            elif key == "files":
                for file_key, file_path in value.items():
                    value[file_key] = open(file_path, 'rb')
        res = RequestUtil.sess.request(method, url, **kwargs)
        print(res.text)
        return res
    #断言
    def assert_result(self,yq_result,sj_result,return_code):
        all_flag = 0
        for yq in yq_result:
            for key,value in yq.items():
                print(key,value)
                if key=="equals":
                    flag=self.equals_assert(value,return_code,sj_result)
                    all_flag =all_flag + flag
                elif key == 'contains':
                    flag=self.contains_assert(value,sj_result)
                    all_flag = all_flag + flag
                else:
                    print("框架暂不支持此段断言方式")
        assert all_flag==0

    # 相等断言
    def equals_assert(self,value,return_code,sj_result):
        flag=0
        for assert_key,assert_value in value.items():
            print(assert_key,assert_value)
            if assert_key=="status_code":  #状态断言
                assert_value==return_code
                if assert_value!=return_code:
                    flag=flag+1
                    print("断言失败,返回的状态码不等于%s"%assert_value)
            else:
                lists=jsonpath.jsonpath(sj_result,'$..%s'%assert_key)
                if lists:
                    if assert_value not in lists:
                        flag=flag+1
                        print("断言失败:"+assert_key+"不等于"+str(assert_value))
                else:
                    flag = flag + 1
                    print("断言失败:返回的结果不存在:"+assert_key)
        return flag
    # 包含断言
    def contains_assert(self,value,sj_result):
        flag=0
        if value not in str(sj_result):
            flag = flag + 1
            print("断言失败:返回的结果中不包含:"+value)
        return flag


然后在yaml文件中,输入断言的内容,例如我这个登录接口断言了返回值code是否等于200,以及是否包含data

完成后,让我们run起来,结果可以看到:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【python做接口测试的学习记录day8——pytest自动化测试框架之热加载和断言封装】 的相关文章

随机推荐

  • 微信小程序实现音乐播放器(2)

    文章目录 前情提要 BackgroundAudioManager API wx setNavigationBarTitle 搭建静态资源服务器 小程序项目 app json app wxss pages music music json p
  • three.js常用几何体介绍以及自定义几何体

    一 自定义三角形几何体 核心代码 添加物体 创建几何体 for let i 0 i lt 50 i 每一个三角形 需要3个顶点 每个顶点需要3个值 const geometry new THREE BufferGeometry const
  • 【教程

    文章目录 1 张量 Tensor 2 梯度 PyTorch 1 5 0 autograd 库是使用 PyTorch 构建神经网络的核心 首先让我们简要地浏览一下 之后我们将会训练第一个神经网络 autograd 库提供了 Tensors 上
  • 多线程问题分析thread

    多线程 进程概述 A 进程 进程指正在运行的程序 确切的来说 当一个程序进入内存运行 即变成一个进程 进程是处于运行过程中的程序 并且具有一定独立功能 简而言之 当前正在运动的程序 一个应用程序在内存中的执行区域 B 线程 线程是进程中的一
  • NFTScan 与 Bulletime 在 NFT 底层数据方面达成战略合作

    近日 Web3 基础设施 NFTScan 浏览器与 Bulletime 达成战略合作伙伴关系 双方将在 NFT 底层源数据方面展开深度合作 Bulletime 是一个专业的 NFT 项目链上和链下数据分析聚合平台 为 NFT 用户提供一站式
  • window 分布式文件服务器,Windows活动目录笔记24

    Windows活动目录笔记24 分布式文件系统DFS创建与使用 DFS复制使用复杂的进程保持多个服务器上的数据同步 DFS复制是一个多机复制引擎 一台服务器上的任何修改都将复制到其他所有的成员服务器上 测试环境 域控制器dc1 jinxin
  • 关于xshell的参数配置问题

    关于xshell其实如果想connection通的话 必须需要设置的两个地方如下图 一个是登陆目的主机的IP地址 以及登陆使用的账号和密码另一个就是需要设置代理服务器 类型和端口号是对应的如http1 1对应的是9001 具体对应端口号自己
  • ChatGPT专业应用:采访大纲自动生成

    正文共 429字 阅读大约需要 2 分钟 品牌公关人员 记者群体必备技巧 您将在2分钟后获得以下超能力 1 专业性采访大纲速成 2 多样性采访提问 Beezy评级 B级 经过简单的寻找 大部分人能立刻掌握 主要节省时间 推荐人 麻辣酱 编辑
  • 基于 Matlab 的混沌算法求解单目标优化问题

    基于 Matlab 的混沌算法求解单目标优化问题 随着科学技术的发展和应用场景的不断拓展 优化问题已经成为了一个十分重要的研究领域 在实际问题中 经常需要找到一个最佳解或最优解 从而使得系统能够更加高效地运行 针对这种问题 混沌算法已经被广
  • Flutter输入框实现银行卡输入 每隔四位插入空格进行分割

    先来看下效果图吧 实现思路 1 利用输入框的TextInputFormatter的withFunction方法来处理用户输入的内容 2 同时需要监听文本改变将光标移动至末尾 输入框 CupertinoTextField controller
  • SpringBoot项目 报错 ERROR 13804 --- [ restartedMain] o.a.tomcat.jdbc.pool.ConnectionPool : Unable

    SpringBoot项目 报错 ERROR 13804 restartedMain o a tomcat jdbc pool ConnectionPool Unable 数据库链接出错 通常发生在导入新项目时 MySQL 数据库版本不匹配
  • 浏览器出现光标

    这里想要把光标关掉 解决办法 按键盘的F7 解决办法2 ok 结束
  • 电子书djvu格式简介zz

    DjVu是由美国AT T实验室于1996年开发成功的一项新的图片压缩技术 DjVu的主要技术是将图像分为背景层 纸的纹理和图片 和前景层 文本和线条 通过将文字和背景分离开来 DjVu可以用高分辨率来还原文字 使锐利边缘得以保留 并最大限度
  • 很强,我终于找到绘制E-R图的正确姿势!

    前言 不知道大家是不是和我一样 为了追求速度 开发时一般都是直接建表就干 哪管什么E R图 直到xxx项目找上你 某某客户要E R图 提供一下吧 这时候就很烦 从头绘制E R图成本真的很高 今天我就遇到了这个糟心事 那有什么办法快速从我们的
  • 在使用Assimp库时编译器报错:C2589 “(”:“::”右边的非法标记 AssimpLoadStl

    OpenGL系列文章目录 文章目录 OpenGL系列文章目录 前言 一 错误原因 二 解决 三 运行结果 源码下载 前言 在使用Assimp库时编译器报错 严重性 代码 说明 项目 文件 行 禁止显示状态 错误 C2589 右边的非法标记
  • 大气散射模型的推导过程

    大气中粒子的散射作用是产生雾霾的主要原因 无论是用人的肉眼观察 还是从拍摄获取的图像中观察 雾天的景象总是存在对比度和视野降低的问题 1925年 Keim Nemnich 1 等人提出雾天图像能见度较低是大气中的悬浮粒子对光的吸收和散射造成
  • 吉林大学超星MOOC学习通高级语言程序设计 C++ 实验02 分支与循环程序设计(2021级)(3)

    9 三位Armstrong数 题目编号 Exp02 Basic08 GJBook3 04 12 题目名称 三位Armstrong数 题目描述 编写程序 打印所有3位的Armstrong数 Armstrong数是指其值等于它本身每位数字立方和
  • Dubbo 3.x源码(9)—Dubbo启动元数据中心源码

    基于Dubbo 3 1 详细介绍了Dubbo启动元数据中心源码 Dubbo配置的加载与覆盖的一系列源码文章 Dubbo 3 x源码 7 Dubbo配置的加载入口源码 Dubbo 3 x源码 8 Dubbo配置中心的加载与优先级源码 Dubb
  • 服务器多线路分流自动跳转代码

    代码一 在要跳转的页面上写上
  • 【python做接口测试的学习记录day8——pytest自动化测试框架之热加载和断言封装】

    一 热加载 就是在代码执行过程当中动态的调用Python中的方法达到或得动态参数的目的 在根目录下创建debug talk py 这里我们写入了获得随机数的方法 后面使用值直接调用即可 import random import time f