接口自动化测试框架ApiRunner实战+框架解析

2023-11-04

目录

框架结构

快速尝试

测试文件

测试用例yaml文件

RequestUtil

初始化

standand_yaml

 send_request

read_testcase

参数化

用例关联

断言

test文件封装

pytest配置文件

 conftest.py

 config.yaml

测试报告

 总结


本文介绍一个接口自动化测试框架,只需要编写yaml文件,即可实现接口自动化测试。阅读这个框架的结构并了解代码实现。由于是一个无名的框架,我把它起名叫做ApiRunner。

框架结构

 

快速尝试

程序入口run.py,调用的pytest库执行用例。

执行后,可以看到通过了一条用例。

下面看看测试用例如何执行的。

测试文件

test_login.py中为测试用例

 

 该文件为一个测试类,无继承,每一个test为一个测试函数,这也是pytest中的概念。

该测试函数,采用parametrize进行数据驱动,用read_testcase函数读取login.yaml文件,并起名为caseinfo。

在测试函数中,调用RequestUtil类,传入base_test_url,然后调用standard_yaml函数,解析caseinfo。

测试用例yaml文件

login.yaml文件,按照关键字写好接口测试用例,如name,request,validate部分。 

RequestUtil

初始化

测试用例在初始化该类时,传入的base_test_url来自conifg.yaml文件,作用为读取baseurl的值。

standand_yaml

解析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")

 获取caseinfo中的key,判断是否包含必须的name,request,validate关键字,如果不包含,说明写的用例格式错误(这里限制了必须包含着三个关键字)
获取request中的关键字,判断是否有method和url,没有说明格式错误。
从request中取出method,url,调用send_request方法发送请求。并获取返回结果。
如果caseinfo包含extract关键字,则进行解析,将对应值写给extract.yaml文件,调用assert_result方法进行断言。。

extrat支持正则和jsonpath,提取出的key和value存放在extract.yaml文件中

 

 

 

 

 

 

 send_request

  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)
                print(kwargs[key])
            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

read_testcase

读取yaml数据,以列表嵌套字典形式返回

def read_testcase(yaml_name):
    with open(os.getcwd() + '\\testcases\\' + yaml_name, mode='r', encoding='utf-8') as f:
        caseinfo = yaml.load(f, yaml.FullLoader)
        print((caseinfo))
        if len(caseinfo)>=2:
            return caseinfo
        else:
            if "parameterize" in dict(*caseinfo).keys():
                new_caseinfo = ddt(*caseinfo)
                return new_caseinfo
            else:
                return caseinfo

该函数读取测试用例yaml文件,读取出的caseinfo为一个列表。如果这个列表长度大于等于2,则直接返回,否则如果列表转换后的字典有parameterize关键字,则用ddt函数进行解析,返回new_caseinfo,否则直接返回caseinfo。

[{'name': '$ddt{name}', 'request': {'method': 'post', 'url': '/auth/login', 'headers': {'Content-Type': 'application/json'}, 'json': {'username': 'tester', 'password': 'tester'}}, 'validate': [{'equals': {'status_code': 200}}]}]c

参数化

在login_data里写测试数据,用parameterize关键字传进去,在测试用例理用$ddt{}进行读取。

 

 

在ddt函数里,对caseinfo中的带$ddt{}的数据进行了替换,返回的new_caseinfo为解析ddt后的数据。

 

在测试数据文件里,还可以直接读取extract.yaml里的值,或者直接运用test.py文件中的函数,如图的调用生成时间函数。 

用例关联

在login.yaml中用extract关键字提取出token,在下一个接口中用read_extract_data进行读取。

之所以能用${}读取值,是因为在send_request里调用了replace_value,将引用替换成了真实的值。

断言

断言目前支持,断言返回状态码和用jsonpath断言值。

方法只支持equals和contains,其他需要自己补充方法。

 

  # 相等断言
    def equals_assert(self,value,return_code,sj_result):
        """

        :param value: 断言字典如{msg:"登录成功"}
        :param return_code: 响应状态码
        :param sj_result: 响应json数据
        :return:
        """
        flag=0
        for assert_key,expect_value in value.items():
            print(assert_key,expect_value)
            if assert_key=="status_code":  #状态断言
                expect_value==return_code
                if expect_value!=return_code:
                    flag=flag+1
                    print("断言失败,返回的状态码不等于%s"%expect_value)
            else:#用jsonpath进行断言
                lists=jsonpath.jsonpath(sj_result,'$..%s'%assert_key)
                if lists:
                    if expect_value not in lists:
                        flag=flag+1
                        print("断言失败:"+assert_key+"不等于"+str(expect_value))
                else:
                    flag = flag + 1
                    print("断言失败:返回的结果不存在:"+assert_key)
        return flag
    # 包含断言
    def contains_assert(self,value,sj_result):
        flag=0
        if str(value) not in str(sj_result):
            flag = flag + 1
            print("断言失败:返回的结果中不包含:"+str(value))
        return flag

test文件封装

test文件封装的是常用的一些方法,可以直接用${函数名}在测试用例中调用,之所以能调用,是因为在replace_value中进行了值替换。

pytest配置文件

pytest.ini文件是pytest的主配置文件,可以改变pytest的运行方式,它是一个固定的文件pytest.ini文件,读取配置信息,按指定的方式去运行。

 

 conftest.py

conftest可以写一些fixture,做一些全局的前后置操作,如清理测试数据,如UI自动化测试中的打开浏览器。

不需要import导入 conftest.py,pytest用例会自动识别该文件,放到项目的根目录下就可以全局目录调用了

 config.yaml

配置文件,可以写一些url,username等配置。

 

测试报告

在run.py里写上allure生成报告的两句命令,执行后即可自动显示allure报告。

 

 总结

这个框架总体来说比较小而美,使用起来简单,结构基本齐全。

缺陷是,框架还有很多优化的空间,如没有封装日志,打印提示很不友好,很多地方没有进行异常处理,断言只支持equals,有兴趣可以继续优化。

 

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

接口自动化测试框架ApiRunner实战+框架解析 的相关文章

  • Python3+Kivy+Plyer 推送通知图标问题

    我在使用 Android 的简单通知测试应用程序时遇到了一个奇怪的错误 错误 python AttributeError type object notification org notificator R drawable has no
  • 在 python 的 Visual Studio 工具中按下 ctrl+F5 后,控制台窗口立即关闭

    我已经安装了 Visual Studio 的 Python 工具 但在控制台窗口中看不到输出 就像我在 Visual Studio 中运行 C 控制台应用程序时按以下快捷键时看到的输出一样 F5 开始调试程序并关闭 C 和 Python 中
  • 根据 pandas 中的条件交换列值

    我想按条件重新定位列 如果国家 地区是 日本 我需要将姓氏和名字反向重新定位 df pd DataFrame France Kylian Mbappe Japan Hiroyuki Tajima Japan Shiji Kagawa Eng
  • 如何 json_normalize() df 中的特定字段并保留其他列? [复制]

    这个问题在这里已经有答案了 这是我的简单示例 我的实际数据集中的 json 字段非常嵌套 因此我一次解压一层 我需要在 json normalize 之后保留数据集上的某些列 https pandas pydata org docs ref
  • DataFrame 中的字符串,但 dtype 是对象

    为什么 Pandas 告诉我我有对象 尽管所选列中的每个项目都是一个字符串 即使在显式转换之后也是如此 这是我的数据框
  • 对打开文件的脚本进行单元测试

    我编写了一个脚本 它打开一个文件 读取内容并进行一些操作和计算 并将它们存储在集合和字典中 我该如何为这样的事情编写单元测试 我的问题具体是 我会测试文件是否打开 文件很大 这是unix字典文件 我如何对计算进行单元测试 我真的必须手动计算
  • 返回不包括指定键的字典副本

    我想创建一个函数 返回字典的副本 不包括列表中指定的键 考虑这本词典 my dict keyA 1 keyB 2 keyC 3 致电without keys my dict keyB keyC 应该返回 keyA 1 我想用一行简洁的字典理
  • 如何在 openpyxl 中设置或更改表格的默认高度

    我想通过openpyxl更改表格高度 并且我希望首先默认一个更大的高度值 然后我可以设置自动换行以使我的表格更漂亮 但我不知道如何更改默认高度 唯一的到目前为止 我知道更改表格高度的方法是设置 row dimension idx heigh
  • 使用 Python 中的 IAM 角色访问 AWS API Gateway

    我有一个 AWS API 网关 我想使用它来保护其安全IAM 角色 http docs aws amazon com apigateway latest developerguide permissions html 我正在寻找一个包来帮助
  • pandas 两个数据框交叉连接[重复]

    这个问题在这里已经有答案了 我找不到有关交叉联接的任何内容 包括合并 联接或其他一些内容 我需要使用 my function 作为 myfunc 处理两个数据帧 相当于 for itemA in df1 iterrows for itemB
  • 我有一个 Employee 类,我想返回“姓名”列表

    我有一个 Employee 类 我想返回 姓名 列表 雇员 py class Employee object def init self id name members None self id id self name name self
  • 如何像在浏览器中一样检索准确的 HTML

    我正在使用 Python 脚本来呈现网页并检索其 HTML 它适用于大多数页面 但对于其中一些页面 检索到的 HTML 不完整 我不太明白为什么 这是我用来废弃此页面的脚本 由于某种原因 每个产品的链接不在 HTML 中 Link http
  • 将参数传递给 __enter__

    刚刚学习 with 语句尤其是这篇文章 http effbot org zone python with statement htm 问题是 我可以传递一个参数给 enter 我有这样的代码 class clippy runner def
  • python 中的基本矩阵转置

    我尝试了 python 中矩阵转置的最基本方法 但是 我没有得到所需的结果 接下来是代码 A 1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4 print A def TS A B A for i in range len A
  • django如何将字符串转换为模块?

    我试图了解 django 的另一个神奇之处 它可以将字符串转换为模块 In settings py INSTALLED APPS声明如下 INSTALLED APPS django contrib auth django contrib c
  • 向伪 shell (pty) 发出命令

    我尝试使用 subprocess popen os spawn 来运行进程 但似乎需要伪终端 import pty master slave pty openpty os write master ls l 应该发送 ls l 到从属终端
  • dask allocate() 或 apply() 中的变量列名

    我有适用于pandas 但我在将其转换为使用时遇到问题dask 有一个部分解决方案here https stackoverflow com questions 32363114 how do i change rows and column
  • python csv按列转换为字典

    是否可以将 csv 文件中的数据读取到字典中 使得列的第一行是键 同一列的其余行构成列表的值 例如 我有一个 csv 文件 strings numbers colors string1 1 blue string2 2 red string
  • Pandas DataFrame:如何计算组中第一行和最后一行的差异?

    这是我的熊猫数据框 import pandas as pd import numpy as np data column1 338 519 871 1731 2693 2963 3379 3789 3910 4109 4307 4800 4
  • Python“self”关键字[重复]

    这个问题在这里已经有答案了 我是 Python 新手 通常使用 C 最近几天开始使用它 在类中 是否需要在对该类的数据成员和方法的任何调用前添加前缀 因此 如果我在该类中调用方法或从该类获取值 我需要使用self method or sel

随机推荐

  • RFID自助借还书机给图书馆带来的优势

    自助借还书机系统是智慧图书馆的主要组成部分 自助借还书机系统主要通过对粘贴有电子标签或条形码的图书进行扫描识别 将其信息反馈到自助借还书机系统当中进行处理 自动完成借阅与归还 自助借还书机的操作页面简洁 用户操作快捷方便 而且其硬件设备简洁
  • 李沐大神动手学深度学习——学习笔记(不定期连载)

    最近在看李沐大佬的动手学深度学习 讲的非常基础 从很基础的开始讲 很易懂 这里记一些在之前没碰到过的在他代码里出现过的写法 and一些问题 当做学习记录 不定期连载更新 简单的目录 前12集 1 torch的tensor高级索引用法 2 p
  • 《machine learning》3线性代数

    3 1 矩阵和向量 矩阵Matrix Recrangular array of numbers R 4 2 R 4 2 R4 2 4行2列矩阵 矩阵的项
  • 开源api_开源IP地理位置API

    开源api Geo location is the identification or estimation of the real world geographic location of an Internet connected co
  • 解决falcon不能注册的问题

    参照
  • 导出开发板根文件系统rootfs

    环境 1 Windows子系统Linux Ubuntu18 没有安装子系统的 虚拟机也是一样 需要注意的是Windows子系统Linux Ubuntu18需要是WSL2版本 2 开发板RK3288 安装SSH 并允许root登录 3 开发板
  • Week 3 Git&Github: create a branch and push it to remote

    本节讲 在本地仓库创建分支之后 怎么同步到远程仓库 用到的命令有 git checkout b newbranch 创建并跳转到新的分支 git commit a m 提交更改 git push u origin newbranch 向远程
  • 【案例】航班准点分析

    文章目录 1 数据集 2 数据探索和清洗 3 起飞以及到达延迟情况 4 数据库样式 1 数据集 数据集为美国各州机场的航班信息 包含出发地 目的地 是否出发延迟15分钟 是否到达延迟15分钟等 https www transtats bts
  • 请你设计一个可以解释字符串 command 的 Goal 解析器

    1678 设计 Goal 解析器 请你设计一个可以解释字符串 command 的 Goal 解析器 command 由 G 和 或 al 按某种顺序组成 Goal 解析器会将 G 解释为字符串 G 解释为字符串 o al 解释为字符串 al
  • kaggle数据科学从业者分析报告

    数据科学从业者调查python语言分析 数据描述 2017年8月26日 全球最大的数据科学社群Kaggle发布了数据科学 机器学习业界现状全行业调查的数据集 调查问卷数据从2017年8月7日 8月25日收集 受访者囊括了来自50多个国家的1
  • H.264 入门篇 - 11 (帧间预测 - DPB 管理策略)

    DPB 对解码图像的存储有个策略 更倾向于存储对后面编码有用的图像 也就是参考图像 虽然说 DPB 中也可以存储非参考图像 在DPB没满的时候 会无差别地把参考图像与非参考图像一并插入DPB中 但是一旦DPB满了之后 如果新重建的图像为参考
  • 计算1-1/2+1/3-1/4+...-1/100的几种算法总结

    计算1 1 2 1 3 1 4 1 100 int main 法一 double n 1 double sub 0 double trem 0 double q 1 for n 1 n lt 101 n trem q 1 0 n sub s
  • 2021较全 腾讯云服务器安装宝塔面板建网站全过程(图文教程)

    2021最全 腾讯云服务器安装宝塔面板建网站全过程 图文教程 1 购买 首先 咱们在安装宝塔面板之前 我们需要先有一个服务器 可以访问这里 专业的公司 或者不差钱的推荐点腾讯云主页 这是云服务器CVM 点这里链接 或者 轻量级服务器 点这个
  • ELK+Filebeat日志分析系统

    目录 一 ELK基本介绍 1 ELK是什么 2 组件简介 2 1 ELK组件介绍 2 2 ELFK组件介绍 2 3 其它组件 4 使用ELK的原因 5 完整日志系统的基本特征 二 Elasticsearch的介绍 三 Logstash的介绍
  • osg示例解析之osganimationmorph(1)

    本课主要演示了osgAnimation中的变形动画 变形动画通常也称为逐顶点动画 Per vertex Animation 是一种三维动画的表现形式 它对计算机的运算资源的消耗很大 通常以每帧计算和应用4000 9000个顶点的位置变化为宜
  • Java中如何读取和写入properties文件

    properties文件是一种属性文件 这种文件以key value格式存储内容 Java中可以使用Properties类来读取这个文件 一般properties文件作为一些参数的存储 使得代码更加灵活 这里先定义一个data proper
  • Tinyhttp学习之路

    写在前面 最近在学习Linux网络编程 对客户端 服务端有了大致了解 纸上得来终觉浅 总觉得理解得不够彻底 于是在网上找了一个开源代码学习 tinyhttpd是一个超轻量型Http Server 使用C语言开发 全部代码只有502行 包括注
  • linux 上个命令返回值,Linux命令的返回值

    在 Linux 下 不管你是启动一个桌面程序也好 还是在控制台下运行命令 所有的程序在结束时 都会返回一个数字值 这个值叫做返回值 或者称为错误号 Error Number 在控制台下 有一个特殊的环境变量 保存着前一个程序的返回值 我们可
  • ECharts常用配置项

    ECharts常用配置 setOption 绘制图表 使用 echarts 实例的 setOption 可以设置图表实例的配置项以及数据 万能接口 所有参数和数据的修改都可以通过 setOption 完成 调用方式 myChart setO
  • 接口自动化测试框架ApiRunner实战+框架解析

    目录 框架结构 快速尝试 测试文件 测试用例yaml文件 RequestUtil 初始化 standand yaml send request read testcase 参数化 用例关联 断言 test文件封装 pytest配置文件 co