玩界WanJie购物商城接口自动化项目架构介绍

一.项目介绍

基于Python+pytest+sqlalchemy+requests+allure+jsonpath+yaml+Jenkins+Linux

该项目是⼀个专注于游戏生态的在线购物平台,致力于为全球玩家打造⼀站式的购物体验。平台涵盖热门游戏本体、电竞外设、虚拟道具、会员订阅、游戏周边等丰富商品,⽀持用户注册、登录、商品浏览、下单支付、商家上架/下架管理等功能模块

二.项目结构说明

点击查看代码
project-root/                          # 项目根目录
├─ base/                               # 基础类封装(核心功能)
│  ├─ api_request.py                   # 接口请求基类(封装requests)
│  ├─ test_case_tools.py               # 测试用例工具类(如数据处理、断言)
│  └─ driver.py                        # 浏览器驱动封装(可选,UI自动化用)
├─ common/                             # 公共方法封装(可复用工具)
│  ├─ log_utils.py                     # 日志处理工具
│  ├─ excel_parser.py                  # Excel数据解析工具
│  ├─ yaml_parser.py                   # YAML数据解析工具
│  └─ db_operation.py                  # 数据库操作工具(如MySQL)
├─ conf/                               # 全局配置目录
│  ├─ config.ini                       # 环境配置文件(API地址、账号等)
│  ├─ allure_config.yml                # Allure报告自定义配置
│  └─ env.py                           # 环境变量管理文件
├─ data/                               # 测试数据目录
│  ├─ api_data/                        # 接口测试数据
│  │  ├─ login_data.yaml                # 登录接口测试用例数据
│  │  └─ order_data.xlsx                # 订单接口Excel数据
│  └─ ui_data/                          # UI自动化测试数据(可选)
│     └─ page_elements.yaml             # 页面元素定位数据
├─ logs/                               # 测试日志目录(自动生成)
│  └─ test_20231001.log                 # 按日期命名的日志文件
├─ report/                             # 测试报告目录
│  ├─ allure_html/                      # Allure交互式报告(自动生成)
│  ├─ tm_report/                        # TMReport表格报告(自动生成)
│  └─ report_config.py                  # 报告生成配置文件
├─ testcase/                           # 测试用例目录
│  ├─ api_test/                         # 接口测试用例
│  │  ├─ test_login.py                  # 登录接口测试类
│  │  └─ test_order.py                  # 订单接口测试类
│  └─ ui_test/                          # UI自动化测试用例(可选)
│     └─ test_homepage.py               # 首页UI测试类
├─ venv/                               # 虚拟环境目录(自动生成)
├─ conftest.py                         # pytest全局钩子文件(固定名称)
├─ environment.xml                     # Allure报告环境信息文件
├─ extract.yaml                        # 接口依赖参数存储文件
├─ pytest.ini                          # pytest配置文件(固定名称)
├─ requirements.txt                    # 第三方库依赖清单
└─ run.py                              # 主程序入口(执行测试和生成报告)

三.核心代码

1.程序入口 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')

代码说明:

主程序入口

if __name__ == '__main__':

  • Python 标准写法,表示当脚本作为主程序运行时才执行以下代码块。
  • 防止模块被其他脚本导入时意外执行测试逻辑。

Allure报告处理逻辑
点击查看代码
    if REPORT_TYPE == 'allure':
        pytest.main(
            ['-s', '-v', '--alluredir=./report/temp', './testcase', '--clean-alluredir',
             '--junitxml=./report/results.xml'])

参数说明:

参数 含义
-s 输出所有打印信息(不屏蔽 stdout)
-v 显示详细测试结果
--alluredir=./report/temp 将 Allure 报告数据保存到指定目录
./testcase 指定测试用例所在目录
--clean-alluredir 在每次运行前清空之前的报告数据
--junitxml=./report/results.xml 生成 JUnit XML 格式的测试结果文件

shutil.copy('./environment.xml', './report/temp')

  • 复制环境信息文件 environment.xml 到报告目录中。
  • Allure 报告会读取此文件并显示当前测试环境信息。

os.system(f'allure serve ./report/temp')

  • 使用 Allure CLI 命令启动本地服务器并展示生成的报告页面。
  • 会在默认浏览器中自动打开报告。

2.测试用例testcase

商务管理代码示例:

点击查看代码
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)

代码说明:
@pytest.mark.parametrize 参数化装饰器
@pytest.mark.parametrize('case_info', get_testcase_yaml('./testcase/Business interface/BusinessScenario.yml'))

作用:

  • 实现参数化测试,即一个测试方法可以运行多组不同的输入数据。
  • 每一组 case_info 数据都会触发一次完整的测试执行。

参数说明:

  • 'case_info':表示每组测试数据的变量名,在测试函数中作为参数使用。
  • get_testcase_yaml(...):调用函数读取指定路径下的 YAML 文件内容,返回一个包含多个测试用例的列表。

测试方法定义
def test_business_scenario(self, case_info):

  • 这是一个 pytest 测试方法,每个参数化的 case_info 都会触发一次该方法的执行。
  • self 表示这是类中的一个实例方法(属于 TestEBusinessScenario 类)。
  • case_info 是从 YAML 文件中加载的一条测试用例的数据字典。

执行接口请求和校验
RequestBase().specification_yaml(case_info)
作用:

  • 创建 RequestBase 实例,并调用其 specification_yaml() 方法。
  • 该方法接收当前的测试用例数据 case_info,并根据其中的配置(如 URL、方法、请求头、预期结果等)发送 HTTP 请求。
  • 同时会进行响应断言、日志记录等操作,完成整个接口测试流程。

3.接口测试 specification_yaml() 方法

该方法用于处理 YAML 文件中定义的接口测试用例,包括请求参数构造、动态变量替换、接口调用、响应断言以及数据提取等核心功能。

点击查看代码
    def specification_yaml(self, base_info, test_case):
        """
        接口请求处理基本方法
        :param base_info: yaml文件里面的baseInfo
        :param test_case: yaml文件里面的testCase
        :return:
        """
        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)
            # 处理cookie
            cookie = None
            if base_info.get('cookies') is not None:
                cookie = eval(self.replace_load(base_info['cookies']))
            case_name = test_case.pop('case_name')
            allure.attach(api_name, f'测试用例名称:{case_name}', allure.attachment_type.TEXT)
            # 处理断言
            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, mode='rb')}
 
            res = self.run.run_main(name=api_name, url=url, case_name=case_name, header=header, method=method,
                                    file=files, cookies=cookie, **test_case)
            status_code = res.status_code
            allure.attach(self.allure_attach_response(res.json()), '接口响应信息', allure.attachment_type.TEXT)
 
            try:
                res_json = json.loads(res.text)  # 把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.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

四.自动化测试实践

测试用例

image
实现代码

点击查看代码
import allure
import pytest

from base.generateId import m_id, c_id
from base.apiutil import RequestBase
from common.readyaml import get_testcase_yaml


@allure.feature(next(m_id) + '商品管理(单接口)')
class TestLogin:

    @allure.story(next(c_id) + "获取商品列表")
    @pytest.mark.run(order=1)
    @pytest.mark.parametrize('base_info,testcase', get_testcase_yaml('./testcase/ProductManager/getProductList.yaml'))
    def test_get_product_list(self, base_info, testcase):
        allure.dynamic.title(testcase['case_name'])
        RequestBase().specification_yaml(base_info, testcase)

    @allure.story(next(c_id) + "获取商品详情信息")
    @pytest.mark.run(order=2)
    @pytest.mark.parametrize('base_info,testcase', get_testcase_yaml('./testcase/ProductManager/productDetail.yaml'))
    def test_get_product_detail(self, base_info, testcase):
        allure.dynamic.title(testcase['case_name'])
        RequestBase().specification_yaml(base_info, testcase)

    # @allure.story('检查接口状态')
    # @pytest.mark.parametrize('params', get_testcase_yaml('./testcase/productManager/apiType.yaml'))
    # def test_get_api_type(self, params):
    #     RequestBase().specification_yaml(params)
    #
    # @allure.story('电网系统登录校验')
    # @pytest.mark.parametrize('params', get_testcase_yaml('./testcase/productManager/login_dw.yaml'))
    # def test_get_login_dw(self, params):
    #     RequestBase().specification_yaml(params)

    @allure.story(next(c_id) + "提交订单")
    @pytest.mark.run(order=3)
    @pytest.mark.parametrize('base_info,testcase', get_testcase_yaml('./testcase/ProductManager/commitOrder.yaml'))
    def test_commit_order(self, base_info, testcase):
        allure.dynamic.title(testcase['case_name'])
        RequestBase().specification_yaml(base_info, testcase)

    @allure.story(next(c_id) + "订单支付")
    @pytest.mark.run(order=4)
    @pytest.mark.parametrize('base_info,testcase', get_testcase_yaml('./testcase/ProductManager/orderPay.yaml'))
    def test_order_pay(self, base_info, testcase):
        allure.dynamic.title(testcase['case_name'])
        RequestBase().specification_yaml(base_info, testcase)

测试报告
image

五.结语

本项目基于 pytest + Allure 构建了一套完整、稳定、可扩展的接口自动化测试框架,适用于电商系统的业务流程测试。通过数据驱动、变量替换、断言机制、报告可视化等功能,有效提高了测试效率与质量。未来将持续优化,提升其通用性与智能化水平。

posted @ 2025-06-19 19:07  ReSt_Vikin  阅读(30)  评论(0)    收藏  举报