集物商城接口自动化项目及架构介绍

📅 2026/6/28 9:47:49
集物商城接口自动化项目及架构介绍
一项目介绍基于PythonpytestsqlalchemyrequestsallurejsonpathyamlJenkinsLinux该项目是一个在线购物的商城网站包括用户注册登录下单上架/下架商品下单支付等相关功能二项目结构说明pythonproject/ # 项目根目录 ├─ .agents/ # Claude skills生成目录 │ └─ qa-project-context.md ├─ base/ # 底层基类功能封装 │ ├─ apiutil.py # 通用接口请求基类 │ ├─ apiutil_business.py # 业务接口请求封装 │ ├─ generateId.py # 自动生成业务唯一ID工具 │ ├─ new_testcase_tools.py # 新测试用例生成工具 │ ├─ new_tools.ui │ ├─ removefile.py # 文件清理工具 │ ├─ __init__.py # 标识base为Python可导入包 ├─ common/ # 全局公共功能层 │ ├─ assertions.py # 自定义断言库 │ ├─ connection.py # 数据库连接封装 │ ├─ debugtalk.py # 调试函数库 │ ├─ dingRobot.py # 钉钉机器人 │ ├─ handleExcel.py │ ├─ operationcsv.py # csv数据处理 │ ├─ operxml.py # xml文件解析 │ ├─ Pjenkins.py # jenkins API封装 │ ├─ readyaml.py # yaml读写工具 │ ├─ recordlog.py # 日志封装 │ ├─ semail.py # 邮件推送 │ ├─ sendrequest.py # 简易请求封装 │ ├─ two_dimension_data.py ├─ conf/ # 全局环境配置层 │ ├─ config.ini # 环境配置文件 │ ├─ operationConfig.py # 配置读取工具 │ ├─ setting.py # 项目全局常量 ├─ data/ # 测试数据 │ ├─ loginName.yaml # 登录账号参数化数据 │ ├─ login_data.csv # 登录接口批量测试数据 │ ├─ sql/ # SQL脚本存储目录 │ │ ├─ homePage.xml │ │ └─ newVehicleAddShare.xml │ ├─ vehicleNo.csv │ └─ 测试数据.xls ├─ logs/ # 日志文件目录 │ └─ test.20260627.log # 每日运行日志记录请求报文、响应、报错堆栈 ├─ report/ # 测试报告文件 │ ├─ allureReport/ # Allure交互式可视化测试报告 │ ├─ temp/ # 临时缓存目录 │ ├─ results.xml # pytest原生执行结果xml文件 │ └─ tmreport/ │ └─ testReport.html ├─ testcase/ # 测试用例目录 │ ├─ Business interface/ # 业务流程用例 │ │ ├─ BusinessScenario.yml # 业务场景流程定义文件 │ │ ├─ test_business_scenario.py # 业务场景自动化执行脚本 │ ├─ ProductManager/ # 商品管理模块用例包 │ │ ├─ apiType.yaml # 商品模块接口分类配置 │ │ ├─ commitOrder.yaml # 提交订单接口测试参数 │ │ ├─ getProductList.yaml # 商品列表查询接口测试数据 │ │ ├─ login_dw.yaml │ │ ├─ orderPay.yaml │ │ ├─ productDetail.yaml │ │ ├─ test_productList.py │ ├─ Single interface/ # 单接口独立测试用例 │ │ ├─ addUser.yaml # 新增用户接口测试数据 │ │ ├─ deleteUser.yaml # 删除用户接口测试数据 │ │ ├─ queryUser.yaml # 查询用户接口测试数据 │ │ ├─ test_debug_api.py # 单接口调试专用脚本 │ │ ├─ updateUser.yaml # 修改用户接口测试数据 │ ├─ conftest.py # 模块级pytest固件 ├─ venv/ # 项目虚拟环境 ├─ conftest.py # 全局pytest钩子文件 ├─ environment.xml # 多环境切换配置 ├─ extract.yaml # 接口响应提取参数 ├─ pytest.ini # pytest全局配置 ├─ projecttree.md # 项目目录结构说明文档 ├─ requirements.txt # 项目依赖清单 ├─ run.py # 主程序入口三核心代码1程序入口run.py# -*- coding: utf-8 -*- 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(fallure serve ./report/temp) elif REPORT_TYPE tm: pytest.main([-vs, --pytest-tmreport-nametestReport.html, --pytest-tmreport-path./report/tmreport]) webbrowser.open_new_tab(os.getcwd() /report/tmreport/testReport.html)# -*- coding: utf-8 -*-首行注释规定了编码格式utf-8。Linux服务器下Jenkins部署构建项目时出现过中文注释编码的报错。if __name__ __main__:python标准写法程序入口判断当运行本文件时才执行下方逻辑。if REPORT_TYPE allure: pytest.main( [-s, -v, --alluredir./report/temp, ./testcase, --clean-alluredir, --junitxml./report/results.xml])参数说明-s控制台打印print、接口请求/响应日志不捕获标准输出-v详细执行日志展示每条用例名称、成功/失败状态--alluredir./report/temp指定allure原始结果数据输出目录临时缓存执行记录./testcase指定要执行的用例根目录执行testcase下全部测试脚本--clean-alluredir执行前清空./report/temp旧数据避免历史报告干扰shutil.copy(./environment.xml, ./report/temp)shutil文件复制把根目录environment.xml复制到allure临时数据文件夹。并自动读取该文件在报告顶部展示当前测试环境信息。os.system(fallure serve ./report/temp)调用系统命令启动allure本地web服务加载temp目录数据自动弹出浏览器报告。2测试用例层testcase其下包含业务场景流程用例、商品管理模块用例、单接口用例是项目的核心测试用例目录。从单接口测试我们来看编写一个测试用例并发送请求执行做了哪些工作test_debug_api.pypytest.mark.parametrize(base_info,testcase, get_testcase_yaml(./testcase/Single interface/addUser.yaml)) def test_add_user(self, base_info, testcase):装饰器parametrize修饰方法实现参数化数据驱动将yaml文件中的测试用例数据作为参数传入方法内部。装饰器内部调用工具层中封装的get_testcase_yaml函数其中调用了safe_load方法将读取到的yaml流转换为相应的python数据类型并返回。allure.feature(next(m_id) 用户管理模块单接口) class TestUserManager: allure.story(next(c_id) 新增用户) pytest.mark.run(order1) pytest.mark.parametrize(base_info,testcase, get_testcase_yaml(./testcase/Single interface/addUser.yaml)) def test_add_user(self, base_info, testcase): allure.dynamic.title(testcase[case_name]) RequestBase().specification_yaml(base_info, testcase)除了参数化实现数据驱动还需要关注编写allure报告中文档测试内容套件下的内容或测试用例的编号等执行顺序报告埋点等。通过allure装饰器或调用方法实现。以及最后传入参数调用封装在base基类中的方法请求执行。addUser.yaml- baseInfo: api_name: 新增用户 url: /dar/user/addUser method: POST header: Content-Type: application/x-www-form-urlencoded;charsetUTF-8 testCase: - case_name: 正常新增用户 data: username: testadduser password: tset6789890 role_id: 123456789 dates: 2023-12-31 phone: 13800000000 token: ${get_extract_data(token)} validation: - contains: { status_code: 200 } - contains: { msg: 新增成功 } # 异常场景 - case_name: 无效新增·缺少token data: username: testadduser password: tset6789890 role_id: 123456789 dates: 2023-12-31 phone: 13800000000 token: validation: - contains: { status_code: 200 } - contains: { msg: 新增失败 } - case_name: 无效新增·缺少必填参数username data: password: tset6789890 role_id: 123456789 dates: 2023-12-31 phone: 13800000000 token: validation: - contains: { status_code: 200 } - contains: { msg: 新增失败 } - case_name: 无效新增·缺少必填参数role_id data: username: testadduser password: tset6789890 dates: 2023-12-31 phone: 13800000000 token: validation: - contains: { status_code: 200 } - contains: { msg: 新增失败 }yaml文件做的是调用请求前的工作存储数据并进行数据驱动。它的数据基本格式为键值对、列表根据请求规范信息为baseInfo元信息testcase用例数据。baseInfo实现接口元信息复用testcase正反覆盖接口用例数据。3基类封装base基类封装base包含请求底层基础封装、业务接口封装、文件处理工具等是整个项目的核心底层复用目录。前面在testcase的接口用例下最后调用了封装的底层请求基础那么基础封装请求方法中的流程是怎样的需要处理什么def specification_yaml(self, base_info, test_case): 接口请求处理基本方法 :param base_info: yaml文件里面的baseInfo :param test_case: yaml文件里面的testCase :return: #base_info、test_case表示yaml文件中的基础信息和数据已经传入。在编写用例时形参作为字典列表的结构传入。 try: params_type [data, json, params] url_host self.conf.get_section_for_data(api_envi, host) api_name base_info[api_name] # 进行报告埋点 allure.attach(api_name, f接口名称{api_name}, allure.attachment_type.TEXT) url url_host base_info[url] allure.attach(api_name, f接口地址{url}, allure.attachment_type.TEXT) method base_info[method] allure.attach(api_name, f请求方法{method}, allure.attachment_type.TEXT) header self.replace_load(base_info[header]) allure.attach(api_name, f请求头{header}, allure.attachment_type.TEXT) # 提取接口元信息解析url、method、Header cookie None if base_info.get(cookies) is not None: cookie eval(self.replace_load(base_info[cookies])) # 请求参数解析特殊参数单独封装额外转换处理cookie # 请求数据test_case的提取与参数替换将case_name弹出来。 case_name test_case.pop(case_name) allure.attach(api_name, f测试用例名称{case_name}, allure.attachment_type.TEXT) # 调用replace_load方法对数据动态变量替换将原始的断言表达式替换为全局缓存、上一步接口的真实数据 val self.replace_load(test_case.get(validation)) test_case[validation] val validation eval(test_case.pop(validation)) extract test_case.pop(extract, None) extract_list test_case.pop(extract_list, None) # 提取用例基本信息 # 循环动态参数替换处理 for key, value in test_case.items(): if key in params_type: test_case[key] self.replace_load(value) file, files test_case.pop(files, None), None if file is not None: for fk, fv in file.items(): allure.attach(json.dumps(file), 导入文件) files {fk: open(fv, moderb)} # 处理文件上传接口 # 解包运算符解包字典不过不是kwargs是另一个字典。 # 组合完整请求并执行 res self.run.run_main(nameapi_name, urlurl, case_namecase_name, headerheader, methodmethod, filefiles, cookiescookie, **test_case) status_code res.status_code allure.attach(self.allure_attach_response(res.json()), 接口响应信息, allure.attachment_type.TEXT) # 请求方法封装到common.sendrequest.SendRequest # 请求之后获取到响应结果后置阶段将Json格式转为字典类型操作 try: res_json json.loads(res.text) # 把json格式转换成字典字典 if extract is not None: self.extract_data(extract, res.text) # extract接口依赖提取、持久化 if extract_list is not None: self.extract_data_list(extract_list, res.text) # 处理断言 self.asserts.assert_result(validation, res_json, status_code) except JSONDecodeError as js: logs.error(系统异常或接口未请求) raise js except Exception as e: logs.error(e) raise e except Exception as e: raise e调用specification_yaml方法其内部操作逻辑首先要基于try-except异常捕获下统一管控/分层管控。然后操作主要逻辑将传入数据元信息、用例数据用例特殊参数、用例基本参数中的字段提取封装。检查这些参数调用同类下replace_load额外转换处理将yaml数据参数占位符替换解析组合完整请求执行。获取到响应结果通过json.loads将响应文本的字符流文本规范的JSON格式转为python dict类型。然后调用同类下extract_data将响应数据提取出来进行extract全局变量接口依赖。最后调用common下断言处理处理响应结果断言。这就是接口请求处理封装中的主体流程。还有一些需要在操作过程中为allure测试报告埋点。4公共功能层commoncommon目录下包含断言模式封装、钉钉机器人推送、读取yaml文件、记录日志、发送邮件等等公共功能简单介绍一些用到的功能。断言标识FLAG与总断言调度机制两层FLAG标识机制单条断言方法返回局部flag在assert_result总断言调度入口统一累加flag以此判断测试是否通过。def assert_result(self, expected, response, status_code): 断言通过断言all_flag标记all_flag0表示测试通过否则为失败 :param expected: 预期结果 :param response: 实际响应结果 :param status_code: 响应code码 :return: all_flag 0 try: logs.info(yaml文件预期结果%s % expected) # logs.info(实际结果%s % response) # all_flag 0 for yq in expected: # 循环用例validation断言数据 for key, value in yq.items(): # 总断言调度模式与断言标识FLAG的使用 if key contains: flag self.contains_assert(value, response, status_code) all_flag all_flag flag elif key eq: flag self.equal_assert(value, response) all_flag all_flag flag elif key ne: flag self.not_equal_assert(value, response) all_flag all_flag flag elif key rv: flag self.assert_response_any(actual_resultsresponse, expected_resultsvalue) all_flag all_flag flag elif key db: flag self.assert_mysql_data(value) all_flag all_flag flag else: logs.error(不支持此种断言方式) except Exception as exceptions: logs.error(接口断言异常请检查yaml预期结果值是否正确填写!) raise exceptions if all_flag 0: logs.info(测试成功) assert True else: logs.error(测试失败) assert False在testcase parametrize装饰器中调用的方法通过safe_load将任一yaml流转为相应的数据类型返回。def get_testcase_yaml(file): readyaml模块中直接写来调用的函数 , 读取yaml文件中json格式 testcase_list [] try: with open(file, r, encodingutf-8) as f: # safe_load方法用于加载yaml文件返回一个dict 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)})钉钉群聊中给自定义机器人注册webhook地址将静态地址替换到send_dd_msg函数中拼接webhook加时间戳与加密签名推送content_str。def send_dd_msg(content_str, at_allTrue): 向钉钉机器人推送结果 :param content_str: 发送的内容 :param at_all: 全员默认为True :return: timestamp_and_sign generate_sign() # url(钉钉机器人Webhook地址) timestamp sign # url fhttps://oapi.dingtalk.com/robot/send?access_token87bbf28b9c369e886a1f7d746b8abf5e9d3c0acd0894d20ecd2345c083035482{timestamp_and_sign[0]}sign{timestamp_and_sign[1]} timestamp, sign generate_sign() url ( https://oapi.dingtalk.com/robot/send ?access_token87bbf28b9c369e886a1f7d746b8abf5e9d3c0acd0894d20ecd2345c083035482 ftimestamp{timestamp} fsign{sign} ) headers {Content-Type: application/json;charsetutf-8} data { msgtype: text, text: { content: content_str }, at: { isAtAll: at_all }, } res requests.post(url, jsondata, headersheaders) return res.text5其他目录及文件report/测试报告统一输出目录执行自动化用例后自动生成文件资源。内部存放 Allure 执行临时缓存数据、标准 JUnit 结果 xml、静态 HTML 测试报表运行完成后可启动 Allure 服务生成交互式可视化报告同时支持 Jenkins 读取报告统计测试通过率用于流水线结果展示。venv/ 与 requirements.txtvenv/ 为项目独立 Python 虚拟环境可以通过IDE提供服务搭建也可以通过系统基础环境工具命令构建隔离项目依赖包避免多项目包版本冲突。requirements.txt统一记录项目全部第三方依赖pytest、requests、allure、pyyaml、openpyxl 等新环境部署时一键执行即可完整还原运行环境保障团队环境一致性。logs/自动化运行日志归档目录执行用例时自动按日期生成日志文件完整记录接口请求报文、响应内容、报错堆栈、断言失败详情便于线上排查用例失败原因留存测试执行全过程记录支持长期追溯问题。environment.xml全局多环境配置文件存储测试 / 预发 / 生产环境域名、数据库连接信息、账号密钥等环境变量执行用例时框架自动读取配置切换环境同时复制至 Allure 报告目录在可视化报告中展示当前测试环境信息方便区分多轮测试环境。extract.yaml全局参数提取规则配置文件定义接口响应中需要持久化的公共字段token、订单 ID、车辆编号等执行完接口后自动依据配置从返回结果提取对应数据存入全局缓存实现多接口间参数传递完成业务流程串联测试。6Jenkins部署部署环境本地/云服务器Jenkins系统环境项目将Jenkins部署在Tencent云服务器稳定的云端环境提供长期在线公网访问无需依赖本地。放行相应端口。服务器预装JDK、Allure、Maven、Git、Tomcat、Wine兼容 flaskServer.exe 后台服务等环境并配置激活环境变量。通过nohup java -jar jenkins.war --httpPort8080 后台启动Jenkins服务开始使用Jenkins。构建任务Jenkins插件全局工具配置构建过程构建任务需要在Jenkins插件市场安装相应依赖Git、Github拉取Github项目代码、Allure解析并展示可视化测试报告、JUnit解析xml测试结果等等。插件能提供全局工具配置项配置调用服务器本地的第三方工具。然后自定义构建过程包括源码管理、触发器、环境、构建步骤、构建后操作五个阶段完成构建任务。其中有一些障碍点比如说源码管理Credentials账号密码并非password而是Github developer的Token或者说Linux环境的服务器访问Github网络质量不稳定构建时拉取报错换SSH秘钥登录或走网络代理。构建步骤的执行shell需要关注从源码管理拉取源码到/root/.Jenkins/workspace然后执行项目的流程需要做什么。激活虚拟环境安装requirements依赖包运行run.py等等。构建后操作中需要将本地以及Jenkins插件的Allure版本降到2.30.0如此构建后操作才显示提供了Allure report的配置项。四项目结语本项目基于 pytestAllureJenkins 搭建商城接口自动化测试框架实现用例与数据分离、CI 流水线自动执行、可视化报告输出等等。搭建过程中我熟练掌握了 YAML 数据驱动、请求底层封装、全局变量提取、钉钉 / 邮件报告推送、流水线部署整套自动化落地能力。后续计划优化用例自动生成逻辑、补充接口压测扩展、接入 AI 辅助用例编写进一步提升测试效率质量与自动化水平。