Python+Pytest 接口自动化测试框架

一.项目介绍

技术栈:Python+pytest+sqlalchemy+requests+allure+jsonpath+yaml+Jenkins+Linux

针对当当购书平台核心业务链路,搭建接口自动化框架,封装请求逻辑,实现接口关联、响应与数据库双维度校验。

二、项目结构

框架按「解耦分层」设计,每个目录只负责一件事,改代码、改数据不用到处找,核心结构及作用如下:

1 pythonproject/ # 项目根目录 2 ├── base/ # 基础工具层(封装接口、用例生成等核心工具) 3 │ ├── __init__.py # 包标识文件 4 │ ├── apiutil.py # 基础接口请求工具 5 │ ├── apiutil_business.py # 业务接口请求封装 6 │ ├── generateId.py # 测试数据ID生成工具 7 │ ├── new_testcase_tools.py # 自动化用例生成辅助工具 8 │ ├── new_tools.ui # UI类辅助工具 9 │ └── removefile.py # 测试文件清理工具 10 ├── common/ # 公共组件层(封装断言、数据库、通知等公共能力) 11 │ ├── __init__.py # 包标识文件 12 │ ├── assertions.py # 断言工具(接口+数据库校验) 13 │ ├── connection.py # 数据库连接工具(基于SQLAlchemy) 14 │ ├── debugtalk.py # 调试辅助工具 15 │ ├── dingRobot.py # 钉钉机器人通知工具 16 │ ├── handleExcel.py # Excel测试数据处理工具 17 │ ├── operationscsv.py # CSV数据处理工具 18 │ ├── operxml.py # XML文件解析工具 19 │ ├── Pjenkins.py # Jenkins持续集成对接工具 20 │ ├── readyaml.py # YAML配置读取工具 21 │ ├── recordlog.py # 日志记录工具 22 │ ├── semail.py # 邮件通知工具 23 │ ├── sendrequest.py # 请求发送二次封装 24 │ └── two_dimension_data.py # 二维数据处理工具 25 ├── conf/ # 配置层(管理项目环境、系统参数) 26 │ ├── __init__.py # 包标识文件 27 │ ├── config.ini # 项目全局配置文件 28 │ ├── operationConfig.py # 配置文件操作工具 29 │ └── setting.py # 配置项常量定义 30 ├── data/ # 数据层(存储测试数据、SQL脚本) 31 │ ├── sql/ # SQL脚本目录 32 │ │ └── __init__.py # 包标识文件 33 │ ├── login_data.csv # 登录场景测试数据 34 │ ├── loginName.yaml # 登录账号配置 35 │ ├── vehicleNo.csv # 物流模块车辆信息数据 36 │ └── 测试数据.xls # 通用测试数据表格 37 ├── logs/ # 日志层(存储测试执行日志) 38 │ ├── test.20260105.log # 2026-01-05测试日志 39 │ └── test.20260106.log # 2026-01-06测试日志 40 ├── report/ # 报告层(存储测试报告及临时文件) 41 │ ├── allureReport/ # Allure可视化报告生成目录 42 │ ├── temp/ # 报告临时文件目录 43 │ ├── tmreport/ # 自定义格式报告目录 44 │ └── results.xml # Pytest测试结果XML(用于生成Allure报告) 45 ├── test_env/ # 环境层(测试环境依赖配置) 46 │ ├── Include/ # 环境依赖包Include目录 47 │ ├── Lib/ # 环境依赖库目录 48 │ ├── Scripts/ # 环境脚本目录 49 │ └── pyvenv.cfg # 虚拟环境配置文件 50 ├── testcase/ # 用例层(POM模式,按业务拆分) 51 │ ├── Business interface/ # 业务全链路用例目录 52 │ ├── ProductManager/ # 产品模块用例目录 53 │ ├── Single interface/ # 单接口用例目录 54 │ ├── __init__.py # 包标识文件 55 │ └── conftest.py # 用例层局部夹具配置 56 ├── venv/ # 虚拟环境目录(隔离项目依赖) 57 ├── __init__.py # 项目根包标识文件 58 ├── conftest.py # Pytest全局夹具配置 59 ├── environment.xml # Allure报告环境信息配置 60 ├── extract.yaml # 接口关联数据存储文件 61 ├── pytest.ini # Pytest执行规则配置 62 ├── requirements.txt # 项目依赖包清单 63 ├── run.py # 框架执行入口脚本 64 └── 使用前请阅读此文件.md # 项目使用说明文档

附:项目依赖清单(requirements.txt)

pytest==7.4.2

requests==2.31.0

PyYAML==6.0.1

jsonpath-ng==1.6.0

sqlalchemy==2.0.21

pymysql==1.1.0

allure-pytest==2.13.2

三.核心代码模块

1.Pytest 统一配置管理(用例执行规则)

核心文件

  • 根目录 pytest.ini:定义 Pytest 执行规则;
  • 根目录 conftest.py:全局夹具(如接口请求会话、数据库连接初始化);
  • testcase 目录 conftest.py:用例层局部夹具(如链路用例前置登录)。

核心实现(pytest.ini)

[pytest] ;addopts = -vs --alluredir ./report/temp -p no:warnings --clean-alluredir ; ;testpaths = ./testcase/ filterwarnings = error ignore::UserWarning python_files = test_*.py python_classes = Test* python_functions = test 

核心实现(根目录 conftest.py)

# -*- coding: utf-8 -*- import time import pytest from common.readyaml import ReadYamlData from base.removefile import remove_file from common.dingRobot import send_dd_msg from conf.setting import dd_msg import warnings yfd = ReadYamlData() @pytest.fixture(scope="session", autouse=True) def clear_extract(): # 禁用HTTPS告警,ResourceWarning warnings.simplefilter('ignore', ResourceWarning) yfd.clear_yaml_data() remove_file("./report/temp", ['json', 'txt', 'attach', 'properties']) def generate_test_summary(terminalreporter): """生成测试结果摘要字符串""" total = terminalreporter._numcollected passed = len(terminalreporter.stats.get('passed', [])) failed = len(terminalreporter.stats.get('failed', [])) error = len(terminalreporter.stats.get('error', [])) skipped = len(terminalreporter.stats.get('skipped', [])) duration = time.time() - terminalreporter._sessionstarttime summary = f""" 自动化测试结果,通知如下,请着重关注测试失败的接口,具体执行结果如下: 测试用例总数:{total} 测试通过数:{passed} 测试失败数:{failed} 错误数量:{error} 跳过执行数量:{skipped} 执行总时长:{duration} """ print(summary) return summary def pytest_terminal_summary(terminalreporter, exitstatus, config): """自动收集pytest框架执行的测试结果并打印摘要信息""" summary = generate_test_summary(terminalreporter) if dd_msg: send_dd_msg(summary) 

2.YAML+JsonPath 实现用例与参数解耦

核心文件

  • common 目录 readyaml.py:YAML 文件读取工具;
  • 根目录 extract.yaml:接口关联数据存储;
  • data 目录 *.yaml:接口请求参数(如下单接口参数文件 order_params.yaml)。

核心实现(common/readyaml.py)

import yaml import traceback import os from common.recordlog import logs from conf.operationConfig import OperationConfig from conf.setting import FILE_PATH from yaml.scanner import ScannerError def get_testcase_yaml(file): testcase_list = [] try: with open(file, 'r', encoding='utf-8') as f: data = yaml.safe_load(f) if len(data) <= 1: yam_data = data[0] base_info = yam_data.get('baseInfo') for ts in yam_data.get('testCase'): param = [base_info, ts] testcase_list.append(param) return testcase_list else: return data except UnicodeDecodeError: logs.error(f"[{file}]文件编码格式错误,--尝试使用utf-8编码解码YAML文件时发生了错误,请确保你的yaml文件是UTF-8格式!") except FileNotFoundError: logs.error(f'[{file}]文件未找到,请检查路径是否正确') except Exception as e: logs.error(f'获取【{file}】文件数据时出现未知错误: {str(e)}') class ReadYamlData: """读写接口的YAML格式测试数据""" def __init__(self, yaml_file=None): if yaml_file is not None: self.yaml_file = yaml_file else: pass self.conf = OperationConfig() self.yaml_data = None @property def get_yaml_data(self): """ 获取测试用例yaml数据 :param file: YAML文件 :return: 返回list """ # Loader=yaml.FullLoader表示加载完整的YAML语言,避免任意代码执行,无此参数控制台报Warning try: with open(self.yaml_file, 'r', encoding='utf-8') as f: self.yaml_data = yaml.safe_load(f) return self.yaml_data except Exception: logs.error(str(traceback.format_exc())) #部分代码示例

核心实现(common/assertions.py)

import traceback import allure import jsonpath import operator from common.recordlog import logs from common.connection import ConnectMysql class Assertions: """" 接口断言模式,支持 1)响应文本字符串包含模式断言 2)响应结果相等断言 3)响应结果不相等断言 4)响应结果任意值断言 5)数据库断言 """ def contains_assert(self, value, response, status_code): """ 字符串包含断言模式,断言预期结果的字符串是否包含在接口的响应信息中 :param value: 预期结果,yaml文件的预期结果值 :param response: 接口实际响应结果 :param status_code: 响应状态码 :return: 返回结果的状态标识 """ # 断言状态标识,0成功,其他失败 flag = 0 for assert_key, assert_value in value.items(): if assert_key == "status_code": if assert_value != status_code: flag += 1 allure.attach(f"预期结果:{assert_value}\n实际结果:{status_code}", '响应代码断言结果:失败', attachment_type=allure.attachment_type.TEXT) logs.error("contains断言失败:接口返回码【%s】不等于【%s】" % (status_code, assert_value)) else: resp_list = jsonpath.jsonpath(response, "$..%s" % assert_key) if isinstance(resp_list[0], str):.join(resp_list) if resp_list: assert_value = None if assert_value.upper() == 'NONE' else assert_value if assert_value in resp_list: logs.info("字符串包含断言成功:预期结果【%s】,实际结果【%s】" % (assert_value, resp_list)) else: flag = flag + 1 allure.attach(f"预期结果:{assert_value}\n实际结果:{resp_list}", '响应文本断言结果:失败', attachment_type=allure.attachment_type.TEXT) logs.error("响应文本断言失败:预期结果为【%s】,实际结果为【%s】" % (assert_value, resp_list)) return flag #部分代码示例

4.POM 模式分离用例层与驱动层

核心文件

  • testcase 目录 Business interface/test_order_link.py:业务链路用例(仅关注业务逻辑);
  • base 目录 apiutil_business.py:业务驱动层(封装接口调用逻辑)。

驱动层实现(base/apiutil_business.py)

# -*- coding: utf-8 -*- # sys.path.insert(0, "..") from common.sendrequest import SendRequest from common.readyaml import ReadYamlData from common.recordlog import logs from conf.operationConfig import OperationConfig from common.assertions import Assertions from common.debugtalk import DebugTalk import allure import json import jsonpath import re import traceback from json.decoder import JSONDecodeError assert_res = Assertions() class RequestBase(object): def __init__(self): self.run = SendRequest() self.read = ReadYamlData() self.conf = OperationConfig() def handler_yaml_list(self, data_dict): """处理yaml文件测试用例请求参数为list情况,以数组形式""" try: for key, value in data_dict.items(): if isinstance(value, list): value_lst = ','.join(value).split(',') data_dict[key] = value_lst return data_dict except Exception: logs.error(str(traceback.format_exc())) def replace_load(self, data): """yaml数据替换解析""" str_data = data if not isinstance(data, str): str_data = json.dumps(data, ensure_ascii=False) for i in range(str_data.count('${')): if '${' in str_data and '}' in str_data: # index检测字符串是否子字符串,并找到字符串的索引位置 start_index = str_data.index('$') end_index = str_data.index('}', start_index) # yaml文件的参数,如:${get_yaml_data(loginname)} ref_all_params = str_data[start_index:end_index + 1] # 函数名,获取Debugtalk的方法 func_name = ref_all_params[2:ref_all_params.index("(")] # 函数里的参数 func_params = ref_all_params[ref_all_params.index("(") + 1:ref_all_params.index(")")] # 传入替换的参数获取对应的值,*func_params按,分割重新得到一个字符串 extract_data = getattr(DebugTalk(), func_name)(*func_params.split(',') if func_params else "") if extract_data and isinstance(extract_data, list): extract_data = ','.join(e for e in extract_data) str_data = str_data.replace(ref_all_params, str(extract_data)) # 还原数据 if data and isinstance(data, dict): data = json.loads(str_data) self.handler_yaml_list(data) else: data = str_data return data #部分代码示例

用例层实现(testcase/Business interface/test_business_scenario.py

import allure import pytest from common.readyaml import get_testcase_yaml from base.apiutil_business import RequestBase from base.generateId import m_id, c_id # 注意:业务场景的接口测试要调用base目录下的apiutil_business文件 @allure.feature(next(m_id) + '电子商务管理系统(业务场景)') class TestEBusinessScenario: @allure.story(next(c_id) + '商品列表到下单支付流程') @pytest.mark.parametrize('case_info', get_testcase_yaml('./testcase/Business interface/BusinessScenario.yml')) def test_business_scenario(self, case_info): allure.dynamic.title(case_info['baseInfo']['api_name']) RequestBase().specification_yaml(case_info) 

5.parametrize+YAML 适配多场景测试

核心文件

  • data 目录 order_link_data.yaml:多场景测试数据;
  • testcase 目录 Business interface/test_order_link.py:parametrize 读取数据。

多场景数据(data/loginName.yaml)

- baseInfo: api_name: 用户登录 url: /dar/user/login method: post header: Content-Type: application/x-www-form-urlencoded;charset=UTF-8 testCase: - case_name: 用户名和密码正确登录验证 data: user_name: test01 passwd: admin123 validation: - contains: { 'error_code': none } - eq: { 'msg': '登录成功' } extract: token: $.token

6.框架执行入口(run.py)

核心文件:根目录 run.py

import shutil import pytest import os import webbrowser from conf.setting import REPORT_TYPE if __name__ == '__main__': if REPORT_TYPE == 'allure': pytest.main( ['-s', '-v', '--alluredir=./report/temp', './testcase', '--clean-alluredir', '--junitxml=./report/results.xml']) shutil.copy('./environment.xml', './report/temp') os.system(f'allure serve ./report/temp') elif REPORT_TYPE == 'tm': pytest.main(['-vs', '--pytest-tmreport-name=testReport.html', '--pytest-tmreport-path=./report/tmreport']) webbrowser.open_new_tab(os.getcwd() + '/report/tmreport/testReport.html') 

四.项目结语

电商接口自动化的核心是 “高可用、易维护、全覆盖”,本框架通过 “解耦式设计 + 双维度校验 + POM 模式”,既适配了当当购书的核心业务链路,也可快速迁移至其他电商平台。希望本文的实战思路能为测试同学提供参考,让接口自动化真正落地并产生价值。

Read more

Trae x 图片素描MCP一键将普通图片转换为多风格素描效果

Trae x 图片素描MCP一键将普通图片转换为多风格素描效果

目录 * 前言 * 一、核心工具与优势解析 * 二、操作步骤:从安装到生成素描效果 * 第一步:获取MCP配置代码 * 第二步:下载 * 第三步:在 Trae 中导入 MCP 配置并建立连接 * 第四步:核心功能调用 * 三、三大素描风格差异化应用 * 四.总结 前言 在设计创作、社交媒体分享、教育演示等场景中,素描风格的图片往往能以简洁的线条突出主体特征,带来独特的艺术质感。然而,传统素描效果制作需借助专业设计软件(如Photoshop、Procreate),不仅操作复杂,还需掌握一定的绘画技巧,难以满足普通用户快速生成素描的需求。 为解决这一痛点,本文将介绍蓝耘MCP广场提供的图片素描MCP工具(工具ID:3423)。该工具基于MCP(Model Context Protocol)协议开发,支持单张/批量图片转换、3种素描风格切换及自定义参数调节,兼容多种图片格式与中文路径,无需专业设计能力,

By Ne0inhk

YOLOv9农业应用案例:无人机遥感图像作物计数部署

YOLOv9农业应用案例:无人机遥感图像作物计数部署 在农田管理中,准确统计作物数量是评估种植密度、预测产量、指导灌溉和施肥的关键一步。传统人工计数耗时费力,而卫星影像分辨率有限,难以满足单株级识别需求。如今,搭载高清相机的消费级无人机配合先进目标检测模型,正成为农业数字化的新标配。YOLOv9作为2024年发布的最新一代YOLO架构,在小目标检测、低对比度场景和复杂背景干扰下展现出显著优势——它不依赖额外模块就能稳定检出密集排列的玉米苗、水稻秧或果树幼株。本文不讲论文推导,也不堆砌参数指标,而是带你用一个开箱即用的官方镜像,把YOLOv9真正跑在真实的农田遥感图上,完成从数据准备到结果可视化的完整作物计数流程。 1. 为什么选YOLOv9做农业计数 1.1 农业图像的三大难点,YOLOv9怎么破 农田航拍图不是普通照片:植株颜色与土壤接近、幼苗尺寸小(常小于32×32像素)、排列密集且存在遮挡。过去很多模型在这类图像上漏检率高、定位不准。YOLOv9针对这些问题做了本质优化: * 可编程梯度信息(PGI)机制:让网络在训练中自动聚焦于对检测真正重要的特征区域,而不是被背

By Ne0inhk

机器人软件开发会用到哪些编程语言和框架

一、 核心编程语言 在机器人领域,不同的编程语言因其特性被用于不同的模块。 1. C++ * 地位:性能之王,业界标准。是大多数对性能要求高的机器人组件(如实时控制、感知、底层驱动)的首选语言。 * 应用场景: * 实时控制:机器人的运动规划、伺服电机控制等需要毫秒级响应的任务。 * 感知算法:点云处理(PCL库)、SLAM(即时定位与地图构建)、计算机视觉(OpenCV的核心是C++)。 * 高性能中间件:如ROS 2的底层(DDS)和核心客户端库(rclcpp)。 * 优点:执行效率高,对硬件底层控制能力强,资源管理精细。 * 缺点:学习曲线陡峭,代码编写复杂,需要手动管理内存。 2. Python * 地位:胶水语言,算法原型和AI的主力。由于其简洁的语法和丰富的生态,在机器人上层应用和研究中占据主导地位。 * 应用场景: * AI与机器学习:与TensorFlow、PyTorch等框架无缝集成,

By Ne0inhk
《Virt A Mate(VAM)》免安装豪华版v1.22中文汉化整合

《Virt A Mate(VAM)》免安装豪华版v1.22中文汉化整合

Virt-A-Mate》由Meshed VR 所开发的虚拟实境游戏,你也可以通过Oculus Rift 或HTC Vive 头戴式装置来进行互动式游玩,一旦你进入《Virt A Mate》的世界,你几乎会忘乎所以,进入一个全新的世界,这个世界遵循基本的物理定力,也就是说游戏中的头发、衣服都很真实,随着你的动作而产生运动,而玩家也能亲自编辑角色的服装。 VAM整合包 解压后30GB 解压密码在里面 请看清楚 包含vam软件本体,mmd跳舞插件,国漫人物。都在整合包里面! vam是软件不是游戏 但完成跳舞是比较简单的 回复关键词:vam

By Ne0inhk