当前位置: 首页 > news >正文

Pytest+requests进行接口自动化测试8.0(Allure进阶 + 文件上传接口 + 单接口多用例)

Allure进阶

  • 一、Allure进阶
    • 1. 标题后面的参数隐藏及标题动态展示
      • 1)在接口对应的 py 文件中添加 allure 标题展示
      • 2)修改 allure 里的 listener.py 文件
    • 2. 显示 allure 报告的用例顺序
      • 1)模块编号方法
      • 2)用例编号方法
      • 3)模块及用例编号方法使用
  • 二、pytest进阶
    • 1. 文件上传接口
    • 2. 单接口多条测试用例
      • 1)前置条件
      • 2)分别读取YAML文件 baseInfo,test_case
      • 3)拆分使用 baseInfo,test_case
        • 编号生成器
      • 4)修改接口文件

一、Allure进阶

1. 标题后面的参数隐藏及标题动态展示

目标:将yaml文件中的测试用例名动态展示到 allure 中

  • 未修改前
    在这里插入图片描述
    yaml 文件内容为
  test_case:- case_name: 用户名和密码正确登录验证json:username: "{{get_data(username, login_data.csv)}}"   # 注意:传了 filenamepassword: "{{get_data(password, login_data.csv)}}"validation:- contains: {code: "200"}- contains: {message: "成功"}extract:token: '"token":"(.*?)"'

1)在接口对应的 py 文件中添加 allure 标题展示

在这里插入图片描述

选择 allure.dynamic.title

在这里插入图片描述

代码展示

import pytest
import allure
from common.run_yaml import ReadYamlData
from conf.setting import FILE_PATH
from base.apiutil import BaseRequest@allure.feature("登录接口")
class TestLogin:readyaml = ReadYamlData()@allure.story("正确登录")@pytest.mark.parametrize('case_info', readyaml.read(FILE_PATH['login']))def test_case01(self, case_info):allure.dynamic.title(case_info['test_case'][0]['case_name'])BaseRequest().specification_yaml(case_info)

修改之后,标题展示了,但后面参数占位,需隐藏参数

在这里插入图片描述

2)修改 allure 里的 listener.py 文件

若找不到文件位置,cmd输入以下语句

cd C:\
dir /s listener.py

找到文件位置

在这里插入图片描述

双击打开文件

在这里插入图片描述

文件中查找 test_result.parameters.extend 此处为参数展示

在这里插入图片描述
将内容置空,变为 [ ] 空列表

在这里插入图片描述

再次运行成功隐藏参数并正确展示 yaml 标题

在这里插入图片描述

2. 显示 allure 报告的用例顺序

最终效果

在这里插入图片描述

1)模块编号方法

目标: 生成一系列格式为 M01_, M02_, M03_, …, M99_ 的“模块编号”

在 base 下创建 generateId.py 文件

在这里插入图片描述

编写生成模块编号方法

def generate_module_id():"""生产测试模块编号,为了保证allure报告的顺序与pytest设定的执行顺序保持一致:return:"""for i in range(1,100):module_id = 'M' + str(i).zfill(2) + '_'  # zfill(2) 表示将数字补零到 2 位,例如:1 → '01', 10 → '10'yield module_id   # yield可以按序生成,return每次只生成一个m_id = generate_module_id()
  • zfill(2) 表示将数字补零到 2 位,例如:1 → ‘01’, 10 → ‘10’
  • yield可以按序生成,return每次只生成一个

结果展示:

在这里插入图片描述

2)用例编号方法

目标: 生成测试用例编号,格式为 C01_, C02_, …, C99_

在 generateId.py 文件中继续编写方法

在这里插入图片描述

编写生成用例编号方法

def generate_testcase_id():"""生成测试用例编号:return:"""for i in range(1,100):case_id = 'C' + str(i).zfill(2) + '_'yield case_idc_id = generate_testcase_id()

结果展示:

在这里插入图片描述

3)模块及用例编号方法使用

在接口运行文件中使用 c_id ,m_id 方法

引入 base.generateId 中的 c_id , m_id 方法

from base.generateId import c_id,m_id

使用模块编号

@allure.feature(next(m_id) + "登录接口")

使用用例编号

    @allure.story(next(c_id) + "正确登录")

运行文件中整体代码展示

import pytest
import allure
from common.run_yaml import ReadYamlData
from conf.setting import FILE_PATH
from base.apiutil import BaseRequest
from base.generateId import c_id,m_id@allure.feature(next(m_id) + "登录接口")
class TestLogin:readyaml = ReadYamlData()@allure.story(next(c_id) + "正确登录")@pytest.mark.parametrize('case_info', readyaml.read(FILE_PATH['login']))def test_case01(self, case_info):allure.dynamic.title(case_info['test_case'][0]['case_name'])BaseRequest().specification_yaml(case_info)@allure.story(next(c_id) + "错误登录")@pytest.mark.parametrize('case_info', readyaml.read(FILE_PATH['login']))def test_case02(self, case_info):allure.dynamic.title(case_info['test_case'][0]['case_name'])BaseRequest().specification_yaml(case_info)

最终结果展示:

在这里插入图片描述

二、pytest进阶

1. 文件上传接口

注意:文件上传接口一般不需要请求头

testCase:- case_name:导入车辆黑名单文件files:file: ./data/heimingdan online.xlsx

在 apiutil.py 文件 读取yaml测试用例方法 新增内容 - - - 以二进制方式读取文件内容

                # 处理文件上传接口file,files = to.pop('files',None),None   # to为yaml数据 test_case 的拆分if file is not None:for fk,fv in file.items():allure.attach(json.dumps(file), '导入文件')files = {fk:open(fv,mode='rb')}   # 以二进制的方式读取文件内容res = self.send.run_main(name=api_name, url=url, case_name=case_name,method=method, headers=headers, cookies=cookie,file=files, **to)

2. 单接口多条测试用例

1)前置条件

yaml 文件,单接口包含多条测试用例

- baseInfo:api_name: 用户登录url: /api/basic/auth/loginWithoutCheckCodemethod: POSTheader:Content-Type: application/jsoncookies:session: hjsksksjj17272test_case:- case_name: 用户名和密码正确登录验证json:username: "{{get_data(username, login_data.csv)}}"   # 注意:传了 filenamepassword: "{{get_data(password, login_data.csv)}}"validation:- contains: {code: "200"}- contains: {message: "成功"}extract:token: '"token":"(.*?)"'- case_name: 用户名和密码异常登录验证json:username: "{{get_data(username, login_data.csv)}}"   # 注意:传了 filenamepassword: "{{get_data(password, login_data.csv)}}"validation:- contains: { code: "200" }- contains: { message: "成功" }extract:token: '"token":"(.*?)"'

2)分别读取YAML文件 baseInfo,test_case

避免重复写 URL、header、method 等公共信息,提高 YAML 可维护性

在这里插入图片描述

将yaml文件的 baseInfo,test_case 分别读取出来

    def read(self, yaml_file):"""读取 YAML 文件,返回 [(base_info, test_case), ...] 列表用于参数化"""if not os.path.exists(yaml_file):raise FileNotFoundError(f"配置文件不存在: {yaml_file}")with open(yaml_file, 'r', encoding='utf-8') as f:try:datas = yaml.safe_load(f)if not datas:raise ValueError("YAML 文件为空")# 假设 datas 是一个列表,每个元素是一个接口testcase_list = []for item in datas:base_info = item.get('baseInfo')test_cases = item.get('test_case')  # 注意:与 YAML 一致if not base_info or not test_cases:raise ValueError(f"YAML 格式错误:缺少 baseInfo 或 test_case")for case in test_cases:testcase_list.append((base_info, case))return testcase_listexcept yaml.YAMLError as e:raise ValueError(f"YAML 解析错误: {e}")except Exception as e:raise ValueError(f"读取 YAML 失败: {e}")

3)拆分使用 baseInfo,test_case

在这里插入图片描述

在单接口运行文件中添加 baseInfo,test_case 参数

@allure.feature(next(m_id) + "登录接口")
class TestLogin:readyaml = ReadYamlData()@allure.story(next(c_id) + "正确登录")@pytest.mark.parametrize('base_info,test_case', readyaml.read(FILE_PATH['login']))def test_case01(self, base_info,test_case):allure.dynamic.title(test_case['case_name'])BaseRequest().specification_yaml(base_info,test_case)
  • @pytest.mark.parametrize 实现了“一接口多用例”的核心;
  • allure.dynamic.title() 动态设置用例标题,避免所有用例都叫 test_case01
  • next(m_id) 和 next(c_id) 是自定义的编号生成器
编号生成器

在这里插入图片描述

def generate_module_id():"""生产测试模块编号,为了保证allure报告的顺序与pytest设定的执行顺序保持一致:return:"""for i in range(1,100):module_id = 'M' + str(i).zfill(2) + '_'  # zfill(2) 表示将数字补零到 2 位,例如:1 → '01', 10 → '10'yield module_id   # yield可以按序生成,return每次只生成一个def generate_testcase_id():"""生成测试用例编号:return:"""for i in range(1,100):case_id = 'C' + str(i).zfill(2) + '_'yield case_idm_id = generate_module_id()
c_id = generate_testcase_id()

4)修改接口文件

在这里插入图片描述

修改接口文件 baseInfo,test_case 读取

    def specification_yaml(self,base_info,test_case):"""接口请求处理基本方法:param base_info: yaml文件里的baseInfo:param test_case:  yaml文件里的testCase:return:"""try:params_type = ['params', 'json', 'data']cookie = None"""获取接口的基础数据"""base_url = self.conf.get_envi('host')url = urljoin(f"{base_url}", base_info['url'])allure.attach(url, f'接口地址:{url}')api_name = base_info['api_name']allure.attach(api_name, f'接口名称:{api_name}')method = base_info['method']allure.attach(method, f'请求方法:{method}')# 先取出 headers,再替换headers = base_info['header']headers = self.replace_load(headers)allure.attach(str(headers), f'请求头:{headers}', allure.attachment_type.TEXT)try:cookie = base_info.get('cookies')if cookie:cookie = self.replace_load(cookie)cookie_str = json.dumps(cookie, ensure_ascii=False) if isinstance(cookie,dict) else str(cookie)allure.attach(cookie_str, 'Cookie信息', allure.attachment_type.TEXT)except Exception as e:logs.warning(f"处理cookie失败: {e}")"""获取该接口的所有测试用例"""case_name = test_case.pop('case_name')  # 把case_name删除allure.attach(case_name, f'测试用例名称:{case_name}')# 处理断言val = self.replace_load(test_case.get('validation'))test_case['validation'] = valvalidation = test_case.pop('validation')    # 把validation删除# 处理参数提取extract = test_case.pop('extract', None)extract_list = test_case.pop('extract_list', None)  # 把extract_list删除# 处理接口的请求参数for key, value in test_case.items():if key in params_type:test_case[key] = self.replace_load(value)  # 解析value# 处理文件上传接口file,files = test_case.pop('files',None),Noneif file is not None:for fk,fv in file.items():allure.attach(json.dumps(file), '导入文件')files = {fk:open(fv,mode='rb')}   # 以二进制的方式读取文件内容res = self.send.run_main(name=api_name, url=url, case_name=case_name,method=method, headers=headers, cookies=cookie,file=files, **test_case)allure.attach(res.text, f'接口的响应信息:{res}', allure.attachment_type.TEXT)res_json = res.json()if extract is not None:self.extract_data(extract,res.text)if extract_list is not None:self.extract_data_list(extract_list,res.text)# 处理接口断言self.assert_res.assert_result(validation,res_json,res.status_code)except Exception as e:logs.error(e)raise e
  • replace_load 是用于解析 {{get_data(…)}} 这类动态表达式的函数(如正则替换 + CSV 读取))
http://www.dtcms.com/a/490348.html

相关文章:

  • Kubernetes全景解读:从云原生基石到卓越实践
  • 【JUnit实战3_02】第二章:探索 JUnit 的核心功能(一)
  • 计算机视觉(opencv)——实时颜色检测
  • 宣传网站怎么做网站制作洋网络
  • 网站排名优化化快排优化网站服务器搭建的步骤
  • 本地用docling实现pdf转markdown操作笔记
  • iOS 26 APP 性能测试实战攻略:多工具组合辅助方案
  • 《Linux运维总结:基于X86_64+ARM64架构CPU使用docker-compose一键离线部署consul 1.21.5容器版集群》
  • wordpress 购物东莞网站优化方法有哪些
  • 接线盒工程量-图形识别高效运算
  • 后厨手套穿戴检测保障食品安全 手套佩戴检测 未戴手套检测 未佩戴手套实时报警 高危行业手套佩戴实时监控
  • 原位PL光谱测试教学(实操版)
  • 技术报告:高仿真虚构内容对主流大模型的现实感幻觉测试
  • 大模型提示词简介
  • R语言术语(2)
  • 广州网站建设推广谷歌官网首页
  • 【Python】基于Tkinter库实现文件夹拖拽与选择功能
  • Spring Boot 官方文档精解:构建与依赖管理
  • ONLYOFFICE 桌面编辑器9.1版本已发布:PDF密文功能和全新注释、工作表公式优化及文件恢复便捷化等
  • 重视网站阵地建设广州市天河区建设局官方网站
  • QPS、TPS、RPS 详解
  • 零基础从头教学Linux(Day 50)
  • 《计算机操作系统》_理解并发程序的执行_第4次课20250925
  • 结合多技术指标(如MACD、RSI)来验证布林带参数的可靠性
  • 设计师网站pintset广州市住房城乡建设部门户网站
  • 精品下载站百度怎么在视频下方投放广告
  • 智能Agentic业务系统设计:从任务语义到状态流转的全栈思考
  • 【Leetcodenowcode数据结构】单链表的应用(进阶)
  • Python基础语法全解析
  • Spring Boot 3零基础教程,Spring Boot 自定义日志系统,笔记23