Python接口自动化框架

Python3.8

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

Interface

前言

简单讲述框架的使用

本框架主要基于:Python+Pytest+Yaml(Yaml+CSV)+Redis+Allure+Log+Mysql 实现接口自动化框架

Git地址:https://gitee.com/make_a_summer/interface.git

项目作者:唐松(挽一夏)

个人邮箱:tasng@foxmail.com (欢迎探讨学习进步)

实现功能

  • 测试数据隔离,实现数据驱动。使用yaml文件,或者yaml-csv文件实现单接口多组数据
  • 接口关联使用Redis存储数据
  • 支持多接口数据依赖:如A接口需要同时依赖B、C接口的响应数据作为参数。提取接口单个值,提取接口返回列表
  • 数据库断言:直接在测试用例中写入查询的sql即可断言,无需编写代码
  • 动态多断言: 如接口需要同时校验响应数据和sql校验,支持多场景断言
  • 日志模块: 打印每个接口的日志信息
  • 支持mock接口
  • 统计接口的运行时长
  • 自定义拓展字段: 如用例中需要生成的随机数据,可直接调用

运行接口框架前准备

1. 安装Python
2. 安装依赖库,pip install -r requirements.txt
3. 配置config.yaml文件,配置测试环境,redis,数据库信息等。
   	redis安装,配置账号密码。我是默认安装,没有配置账号密码

切换环境:

  1. config.yaml文件中,增加环境变量,格式固定按照写就好了。记得把变量都写死

  2. config.py文件,修改环境变量

    Ps: 想再不同环境中,都能执行代码,前提是一些变动字段,都写到config.yaml维护,不同环境中维护一套字段。

目录架构

|-common				        		      // 辅助类,用于整个测试框架
|	└── debugtalk.py				          // 自定义函数供测试脚本调用。生成随机数、日期时间戳等常用的功能
|-config				        			  // 配置
|	└── config.py				        	  // 读取项目配置文件:config.yaml		
|	└── config.yaml				              // 项目配置文件
|	└── redis_config.py				          // redis读取/写入方法
|	└── setting.py				        	  // 项目基础路径
|-data				        			      // CSV测试文件
|-files				        				  // 上传文件
|-logs		        				          // 日志
|-reports				        			  // 测试报告		
|-testcase				        			  // 测试用例
|-conftest.py				        		  // 运行前之前操作,清空redis
|-util_tools				        		  // 工具库文件
|	└── db_connector				          // 数据库模块
|	    └── mysql_util.py				      // MySQL工具类
|	└── handle_data				          	  // 测试文件操作模块
|	    └── csv_analysis_params.py	 	      // Yaml文件使用CSV格式,进行数据处理
|	    └── csv_handler.py				      // 读取CSV文件
|	    └── yaml_handler.py				      // 读取Yaml文件
|	└── other_util				        	  // 其他工具类
|	    └── allure_type.py				      // Allure报告步骤中,数据格式处理
|	    └── genrate_id.py				      // 测试用例ID
|	└── notify				        	  	  // 通知
|		terminal
|		    └── terminal_reporter.py		  // 控制台打印样式
|     	└── wechat_work_notifier.py 	      // 企业微信通知
|    	└── email_notifier.py			      // 邮件通知
|     	└── notify_sender.py				  // 配置发送通知类型
|	└── yaml_process				          // Yaml文件处理
|	    └── yaml_analysis.py				  // Yaml数据规范、替换、发送请求、数据提取、执行断言
|	    └── yaml_extract.py					  // 处理数据提取
|	    └── yaml_replace.py					  // 处理数据替换
|	└── assertion_util.py				      // 封装断言
|	└── mock_util.py				          // 封装mock
|	└── redis_util.py					      // 封装redis
|	└── logger_util.py				          // 封装日志
|	└── requests_util.py					  // 封装发送请求
|-conftest.py				        		  // 收集运行时间等
|-pytest.ini				
|-environment.xml						      // allure报告中环境配置
|-run.py									  // 运行入口

接口文档

微信公众号-标签管理:
https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html
在这里插入图片描述

微信公众号-标签管理
登录
查询标签
修改标签
删除标签
文件上传

这位博主的评论区下有接口可以练习,在windows下直接运行就可以用,我之前写了,可以跑通。

现在换了Mac本后不能运行他的接口,懒得在继续搞了,随即放弃。有兴趣的朋友,记得看完他的视频,操作下,非常有必要。

B站博主学习资料,且配套测试接口。

https://b23.tv/0Qlxedq

博主视频评论区中,有练习接口

测试用例

创建测试用例

在testcase目录下分别创建两个文件,yaml文件存储测试数据,py文件运行。

​ 比如在testcase目录userManager文件下新建用户查询接口测试

  • 创建YAML测试文件,编写接口数据
-
  name: 用户查询
  base_url: ${get_base_url(base_url)}
  request:
    headers: ${get_headers(data)}
    method: post
    path: /dar/user/queryUser
    data:
      user_id: 123839387391912
  extract:
  validation:
    - code: 200
    - contain: { "msg": "查询成功!" }
  • 创建执行YAML的Py文件,进行读取YAML文件,发送接口请求
@allure.feature(next(m_id) + '用户管理模块')
class TestUserManager:
    @allure.story(next(c_id) + '用户查询')
    @allure.description('用户查询接口')
    @pytest.mark.parametrize('caseinfo', read_testcase_file('testcase/userManager/queryUser.yaml'))
    def test_user_query(self, caseinfo):
        allure.dynamic.title(caseinfo['name'])
        YamlAnalysis().yaml_analysis_execution(caseinfo)

YAML用例格式规范

YAML测试文件,编写接口数据,其中有严格的关键字层级,编写时需遵守

-
  name:           			# 用例名称
  base_url:       			# 用例基础URL
  request: 
    headers:      			# 请求头  (可选)
    cookies:      			# cookies (可选)
    method:      				# 请求方式
    path:         			# 接口请求路径
    data/json/params:   # 请求参数  (可选)
  extract:        			# 提取参数  (可选)
  # extract_list:  			# 提取参数列表
  validation:    				# 断言

必填项:

​ 4个一级关键字:name、base_url、request、validation

​ 2个二级关键字:method、path

选填项:

​ extract:提取接口返回值中,单个key的值

​ extract_list:提取接口返回值中,指定key的所有值列表

YAML用例数据编写

一个YAML文件管理,能管理一组或者多组数据。YAML文件中有几组数据,就发送几次请求。

​ yaml文件中有两组测试数据,所以能执行两次请求

-
  name: wx_获取token成功
  base_url:  ${get_base_url(base_wx_url)}
  request:
    method: post
    path: /cgi-bin/token
    data:
      grant_type: client_credential
      appid: wx2a3d01a57cd117f4
      secret: 938fa8f53264eecf325dcd67546c747e
  extract:
    access_token: $.access_token
  validation:
    - contain: expires_in
    
-
  name: wx_获取token失败
  base_url:  ${get_base_url(base_wx_url)}
  request:
    method: post
    path: /cgi-bin/token
    data:
      grant_type: 
      appid: wx2a3d01a57cd117f4
      secret: 938fa8f53264eecf325dcd67546c747e
  extract:
  validation:
    - contain: errcode

在这里插入图片描述

YAML+CSV管理用例

看上方发现,在YAML文件中管理多组测试数据,一组两组还好,多了之后YAML中数据就过多,不好查看与管理。

所有就引入了CSV管理,对可变的参数进行处理

  • 1、CSV文件存储在data目录下

  • 2、使用CSV方式做参数化,在YAML文件中,要做对应修改,新增关键字parameters,与对应的读取数据格式$csv{XXX}

下面使用同一个接口,展示CSV管理用例

1、data目录下,新建CSV文件,有四个字段需要被替换使用

name,appid,secret,grant_type,validation
csv-获取token,wx2a3d01a57cd117f4,938fa8f53264eecf325dcd67546c747e,client_credential,access_token
csv-appid必须检查,"",938fa8f53264eecf325dcd67546c747e,client_credential,errcode
csv-appid错误检查,111111111111111,938fa8f53264eecf325dcd67546c747e,client_credential,errcode
csv-secret缺失,wx2a3d01a57cd117f4,"",client_credential,errcode
csv-secret错误检查,wx2a3d01a57cd117f4,22222222222222,client_credential,errcode
csv-grant_type缺失,wx2a3d01a57cd117f4,938fa8f53264eecf325dcd67546c747e,"",errcode
csv-grant_type错误检查,wx2a3d01a57cd117f4,938fa8f53264eecf325dcd67546c747e,1111111111111,errcode

2、YAML测试文件,加入 parameters 字段,并将csv文件路径传入。被替换的字段用$csv{XXX}格式

-
  name: $csv{name}
  base_url: ${get_base_url(base_wx_url)}
  # 使用csv格式,就要加入'parameters'字段。需要替换的数据使用$csv{}进行替换
  parameters:
    name-appid-secret-grant_type-validation: data/wx_tag_login.csv
  request:
    method: post
    path: /cgi-bin/token
    data:
      appid: $csv{appid}
      secret: $csv{secret}
      grant_type: $csv{grant_type}
  extract:
    access_token: $.access_token
  validation:
    - contain: $csv{validation}

在这里插入图片描述

用例中提取参数

提取参数有两个方式,根据接口实际结果使用。支持使用jsonpath正则表达式。提取的接口关联参数存储到:redis 文件中

extract :提取单个数据

extract_list : 提取的数据是列表

提取单个数据

不指定参数提取

适用于接口返回值中,只有一组数据。

比如创建接口,返回值需要提取id。使用jsonpath提取参数,并存入Redis中

创建接口返回接口:

{"tag": {"id": 268, "name": "test86483"}}

yaml文件中,使用jsonpath提取tag下的id,存入Redis中

-
  name: wx-创建标签
  base_url:  ${get_base_url(base_wx_url)}
  request:
    method: post
    path: /cgi-bin/tags/create?access_token=${get_extract_data(access_token)}
    json:
      tag:
        name: test${get_random_number(10000, 99999)}
  extract:
    tag_id: $.tag.id
  validation:
    - code: 200

运行成功后,成功写入Redis中
在这里插入图片描述

提取指定参数

适用于接口返回中存在多组数据。

比如查询接口中,提取name = case86的id,做接口关联时候,为了保持数据的一致性。就要提取指定数据。

查询接口返回值

{
  "tags": [
    {
      "id": 2,
      "name": "星标组",
      "count": 0
    },
    {
      "id": 100,
      "name": "22214767",
      "count": 0
    },
    {
      "id": 129,
      "name": "case",
      "count": 0
    },
    {
      "id": 130,
      "name": "case60",
      "count": 0
    },
    {
      "id": 131,
      "name": "case86",
      "count": 0
    },
    {
      "id": 153,
      "name": "哈哈哈63",
      "count": 0
    },
    {
      "id": 154,
      "name": "哈哈哈45",
      "count": 0
    },
    {
      "id": 155,
      "name": "哈哈哈54",
      "count": 0
    }
  ]
}

yaml文件中,使用jsonpath提取name = case86下的id,存入Redis中

-
  name: wx-查询标签
  base_url:  ${get_base_url(base_wx_url)}
  request:
    method: post
    path: /cgi-bin/tags/get?access_token
    params:
      access_token: ${get_extract_data(access_token)}
  extract:
    caseid: "$.tags[?(@.name=='case86')].id"
  validation:
    - code: 200
    - contain: name

指定提取name = case86下的id,存入Redis中
在这里插入图片描述

提取列表

查询标签接口,返回值中所有的id。分别使用正则与jsonpath提取,使用extract_list关键字

接口返回

{
  "tags": [
    {
      "id": 2,
      "name": "星标组",
      "count": 0
    },
    {
      "id": 100,
      "name": "22214767",
      "count": 0
    },
    {
      "id": 129,
      "name": "case",
      "count": 0
    },
    {
      "id": 130,
      "name": "case60",
      "count": 0
    },
    {
      "id": 131,
      "name": "case86",
      "count": 0
    },
    {
      "id": 153,
      "name": "哈哈哈63",
      "count": 0
    },
    {
      "id": 154,
      "name": "哈哈哈45",
      "count": 0
    },
    {
      "id": 155,
      "name": "哈哈哈54",
      "count": 0
    }
  ]
}

正则提取,提取列表使用extract_list关键字,提取所有id值

-
  name: wx-查询标签
  base_url:  ${get_base_url(base_wx_url)}
  request:
    method: post
    path: /cgi-bin/tags/get?access_token
    params:
      access_token: ${get_extract_data(access_token)}
  extract_list:
    all_ids: '"id":\s*(\d+)'
  validation:
    - code: 200
    - contain: name

jsonpath提取,提取列表使用extract_list关键字,提取所有goodsId值

-
  name: wx-查询标签
  base_url:  ${get_base_url(base_wx_url)}
  request:
    method: post
    path: /cgi-bin/tags/get?access_token
    params:
      access_token: ${get_extract_data(access_token)}
  extract_list:
    all_ids: "$.tags[*].id"
  validation:
    - code: 200
    - contain: name

运行成功,存入Redis中
在这里插入图片描述

参数使用

单个参数使用

这一步就是接口关联的实际用法。上一个接口返回值中提取后存入,下一个接口中读取使用

固定格式写法:${get_extract_data(xxx)}

比如查询标签—编辑标签接口

查询标签,提取name = case86的id,编辑标签中使用该id

-
  name: wx-编辑标签
  base_url:  ${get_base_url(base_wx_url)}
  request:
    method: post
    path: /cgi-bin/tags/update?access_token= ${get_extract_data(access_token)}
    json:
      tag:
        id: ${get_extract_data(caseid)}
        name: test${get_random_number(100000, 999999)}
  extract:
  validation:
      - code: 200
      - contain: ok
多个参数使用

上面提取了列表,并存储,那么就到了使用的时候

Redis中,存入多个值,yaml文件中引用。 id: ${get_extract_data(all_ids,1)},根据索引取第一个值。0随机取值,-1取全部值。方法在debugtalk.py文件中,可以自行扩展。

-
  name: wx-编辑标签
  base_url:  ${get_base_url(base_wx_url)}
  request:
    method: post
    path: /cgi-bin/tags/update?access_token= ${get_extract_data(access_token)}
    json:
      tag:
        id: ${get_extract_data(all_ids,1)}
        name: test${get_random_number(100000, 999999)}
  extract:
  validation:
      - code: 200
      - contain: ok

用例中接口传参如何实现

1、通过上个接口发送请求,得到token请求值,存储到redis中

2、YAML文件中,通过debugtalk.py文件中,使用read_extract_redis方法,获取redis中数据

读取关联值,因为提取的有单个数据、列表数据,所以提取的方式略有不同

单个参数,如上述token值,在YAML文件中,使用${get_extract_data(token)}

列表参数,如上述goodIds第1个值,在YAML文件中,使用${get_extract_data(goodIds,0)}

redis中,已经存储数据

编写方式,需要替换取extract.yaml文件值的地方,使用$ {get_extract_data(xxx)},列表使用${get_extract_data(xxx,位数)}

# 微信删除标签接口,如需传入token
params:
  token: ${get_extract_data(token)}

# 编辑标签中,如想编辑第1个标签,就取第一个id值:2
json:
  id: ${get_extract_data(all_ids,1)}

用例中函数扩展使用

在使用的过程中,发现需要扩展一些方法函数,可以在debugtalk.py文中编写实现。比如看例子时候发现,URL、headers、cookies都是 x x ( ) 格式。这就是在 d e b u g t a l k . p y 文件中定义了写函数,并进行替换使用。如 ‘ {xx()} 格式。这就是在debugtalk.py文件中定义了写函数,并进行替换使用。如 ` xx()格式。这就是在debugtalk.py文件中定义了写函数,并进行替换使用。如{get_base_url()}、${get_headers()}、 ${get_extract_data(Cookie)}`

这些方法均在debugtalk.py文件中编写,yaml用例中使用。

class DebugTalk:
    
	# 基础url
    @classmethod
    def get_base_url(cls, node_name):
        """
        :param node_name: base_url
        :return:
        """
        return read_config_file('base', node_name)
	
    # mysql数据库
    @classmethod
    def get_mysql_config(cls, node_name):
        """
        :param node_name: mysql
        :param node_name:
        :return:
        """
        return read_config_file('mysql', node_name)

    # headers请求头
    @classmethod
    def get_headers(cls, params_type):
        headers_mapping = {
            'data': {'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'},
            'json': {'Content-Type': 'application/json;charset=UTF-8 '}
        }
        header = headers_mapping.get(params_type)
        if header is None:
            raise ValueError('不支持其他类型的请求头设置')
        return header
	
    # 随机数
    @classmethod
    def get_random_number(cls, min, max):
        return random.randint(int(min), int(max))
    

微信创建标签接口时,就可以使用随机数函数

-
  name: wx-创建标签
  base_url:  ${get_base_url(base_wx_url)}
  request:
    method: post
    path: /cgi-bin/tags/create?access_token=${get_extract_data(access_token)}
    json:
      tag:
        name: test${get_random_number(10000, 99999)}
  extract:
  validation:
    - code: 200

断言类型

本框架只实现了五种类型断言

状态码断言、包含模式断言、相等断言、不相等断言、数据库断言

  validation:
    - contain: {'msg': '登录成功'}			# 包含模式 
    - code: 200												# 接口的响应状态码断言
    - eq: {'msg': '登录成功'}						# 相等断言
    - ne: {'msg': '登录失败'}						# 不相等断言
    - db: SELECT name, fee FROM testcase.`user` WHERE id=4; # 数据库断言

allure报告

执行run.py文件,在reports文件allures文件下,打开index.html文件,即可查看
在这里插入图片描述

收到邮箱通知
在这里插入图片描述

运行流程详解

1. 本地开启Redis服务后,启动入口:run.py

if __name__ == '__main__':
    pytest.main()  # 运行 pytest 收集并执行测试用例
    shutil.copy('environment.xml', './reports/temps')  # 复制环境信息
    os.system("allure generate reports/temps -o reports/allures --clean")  # 生成 Allure 报告

2. pytest 收集用例(根据 pytest.ini 配置)

  • 测试路径testcase/
  • 文件命名test_*.py
  • 类命名Test*
  • 函数命名test_*
  • 并发执行-n auto(pytest-xdist)—暂时去掉
  • 报告缓存--alluredir=reports/temps

3. 测试用例结构(YAML 驱动)

每个测试用例是一个 YAML 文件,结构如下:

-
  name: wx-编辑标签
  base_url:  ${get_base_url(base_wx_url)}
  request:
    method: post
    path: /cgi-bin/tags/update?access_token= ${get_extract_data(access_token)}
    json:
      tag:
        id: ${get_extract_data(caseid)}
        name: test${get_random_number(100000, 999999)}
  extract:
  validation:
      - code: 200
      - contain: ok

4. 用例解析与执行流程:YamlAnalysis.yaml_analysis_execution()

步骤说明
① 读取 YAML 文件yaml_handler.pyread_testcase_file()
② 参数化替换csv_analysis_params.py → CSV 数据替换 $csv{key}
③ 变量替换yaml_replace.py → 替换 ${get_extract_data(key)}
④ Mock 判断mock_util.py → 如果存在 mock: 字段,则替换真实请求
⑤ 发送请求requests_util.pyexecute_request()
⑥ 提取响应值yaml_extract.pyextract_data() / extract_data_list()
⑦ 断言验证assertion_util.pyassert_result()
⑧ Allure 报告allure.attach() 记录请求、响应、断言、提取数据

5. 断言支持类型

断言类型示例
状态码断言code: 200
包含断言contain: success
相等断言eq: {success: true}
不相等断言ne: {code: 500}
数据库断言db: SELECT COUNT(*) FROM order WHERE id=123

6. 数据传递机制

  • 保存接口提取的值到Redis(如订单号、token)
  • DebugTalk.get_extract_data():在 YAML 中通过 ${} 动态读取
  • write_extract_redis():提取后写入 Redis

7. 日志与异常处理

  • 日志记录logger_util.py → 控制台 + 日志文件(按天轮转)
  • 异常捕获:每个模块都 try-catch 并记录日志,确保失败用例不中断整个流程

8. 报告与通知

  • Allure 报告:自动生成到 reports/allures/index.html
  • 邮件通知conftest.pypytest_terminal_summary() 钩子函数收集结果并发送邮件

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值