Python自动化测试框架系统实现

Flask+TestRunner 自动化测试系统实现

实现了一个前端可以执行测试用例,测试过程查询的一个自动化测试系统,实现效果如下 大佬们 可以评论私信交流代码、思路

一、Flask与TestRunner的协同合作逻辑

Flask(Web管控层)与TestRunner(自动化执行层)围绕"接口传指令、指令生配置、状态互同步、线程隔干扰"构建通用化"管控-执行"闭环,不绑定具体业务场景,可适配各类自动化测试需求,具体协同流程与优势如下:

1. 协同流程(通用化时间线)

  1. 需求触发:前端测试平台/CI/CD工具(如Jenkins)通过Flask的标准化接口,发起测试请求,执行特定用例
  2. 配置转化:包含两个部分,维护测试床(环境信息):"测试环境参数(如域名、账号)、通用配置(如超时时间)",组装成TestRunner可识别的结构化配置;测试套(测试用例),接口触发特定条件下的测试用例。
  3. 任务托管 :Flask通过任务管理器(如TestTaskManager)生成唯一任务ID,启动独立守护线程,将配置传递给TestRunner并触发测试执行;
  4. 执行同步:TestRunner执行过程中,实时记录用例、步骤的状态(如"进行中""通过");Flask通过绑定的TestRunner实例,动态读取执行数据,更新任务进度(如"50%");
  5. 结果反馈:TestRunner执行完成后,Flask收集"用例详情、错误日志、耗时"等结果,通过状态查询接口返回给前端,日志留痕,形成闭环

2. 协同核心优势

  • 职责解耦易扩展:Flask专注"对外交互+任务管控",TestRunner专注"自动化执行",两者代码独立------例如Flask新增"结果导出"接口,TestRunner优化执行速度,互不影响;
  • 多任务并发无阻塞:每个TestRunner实例运行在独立线程,Flask主线程可同时处理多个测试请求,不会因单个任务未完成导致整体卡住;
  • 结果追溯可定位:通过唯一任务ID关联"请求参数→执行过程→结果数据",即使多任务并行,也能快速定位某条用例失败原因。

二、Flask:自动化测试的"对外桥梁"与"任务中枢"

Flask作为Web框架,核心作用是为TestRunner提供"外部交互入口 "和"任务全生命周期管控",屏蔽TestRunner的技术细节,方便测试人员测试的同时,也能让让非技术人员/外部工具也能便捷使用自动化测试能力。

1. 核心功能(通用化能力)

(1)提供标准化测试触发接口
  • 功能说明:开发通用POST接口,接收外部测试请求,支持传递"业务类型、环境标识、自定义参数",并对请求合法性进行校验(如参数是否完整、业务类型是否支持); 1、将测试用例目录下的测试用例全部查询出来,通过路径执行对应测试用例(可增加用例分组) 2、将核心功能测试用例放到单一页面直接执行,可参数化执行核心功能
  • 核心逻辑:外部请求→参数校验→匹配用例列表→组装TestRunner配置→触发执行;
  • 通用价值:解决TestRunner"无法主动接收外部请求"的问题------无论是测试人员通过前端点击按钮,还是CI/CD流水线自动触发,都能通过HTTP接口发起测试,降低使用门槛。同时还可以加入定时任务执行,接入外部办公api,实现长稳测试+监控。
(2)实现任务统一管理
  • 功能说明 :通过单例任务管理器(如TestTaskManager),实现"任务创建、状态跟踪、过期清理":生成唯一任务ID标识每个测试任务,用任务对象(如TestTask)封装"执行状态、进度、绑定的TestRunner实例"
  • 核心逻辑:创建任务→绑定执行引擎→实时更新状态→查询反馈→导入测试报告;
  • 通用价值:避免TestRunner"无管控执行"------测试人员可随时查询任务进度(如"执行到第3步,共5步"),不用等待测试完全结束才知道结果。
(3)保障多任务执行隔离
  • 功能说明:为每个TestRunner实例分配独立守护线程,确保不同任务的执行环境互不干扰(如A任务的接口请求异常不会影响B任务);(限制并发任务数量,避免资源耗尽;)
  • 核心逻辑:接收请求→判断并发数→启动独立线程→执行TestRunner→任务结束回收线程;
  • 通用价值:支持多业务线同时发起测试,且系统稳定性不受影响。

2. 核心价值总结

Flask的核心作用是"让TestRunner的能力可被外部调用、可被管控"------通过标准化接口降低使用门槛,通过任务管理提升可控性,通过线程隔离保障稳定性,是TestRunner与外部系统交互的"中间件"。

三、TestRunner:自动化测试的"执行引擎"

TestRunner作为自动化测试核心执行框架,专注于"接收Flask的配置指令,完成测试用例的加载、执行、结果统计",不关注外部交互,仅聚焦自动化测试本身的标准化流程。

TestRunner的实现就是测试过程

  1. 测试床:先告诉它再哪个环境执行
  2. 测试套:执行哪些用例
  3. 测试数据,执行步骤,是否符合预期
  4. 测试报告

1. 核心功能实现(通用化执行能力)

先写Base基类,测试用例需要继承它。然后在TestRunner中,实例化测试用例,测试用例继承了Base,所以就可以通过把实例化的测试用例,按照先后顺序,执行方法,比如先执行setUp,都是在TestRunner实例化测试用例之后实现的。本质上是继承,实例化,执行方法。

(1)动态加载测试用例
  • 功能说明 :接收Flask传递的"用例路径配置",通过Python动态导入(importlib)加载指定目录下的用例脚本,自动校验用例合法性(如是否继承指定基类、核心方法是否实现);
  • 核心逻辑:接收配置→解析用例路径→动态导入脚本→校验用例格式→统计可用用例数;
  • 通用价值:无需硬编码导入用例,新增用例只需放在指定目录并配置路径,即可实现用例加载
(2)管控用例执行生命周期
  • 功能说明 :标准化每个用例的执行流程------先执行前置步骤(setUp,如初始化请求客户端、登录),再按顺序执行测试步骤(如调用接口、数据校验),最后执行后置步骤(tearDown,如清理测试数据、释放资源);过程中自动捕获异常(断言失败标记"失败",代码错误标记"错误");
  • 核心逻辑:前置步骤→步骤执行→异常捕获→后置步骤→结果记录;
  • 通用价值:确保所有用例执行流程统一,避免因个人编写习惯不同导致用例结构混乱,同时精准记录每个步骤的状态、耗时,便于问题定位。
(3)生成结构化执行结果
  • 功能说明 :执行完成后,自动统计"测试套整体状态(通过/失败)、用例级详情(每个用例的状态、耗时)、步骤级详情(每个步骤的状态、错误日志)",并提供标准化方法(如get_test_instances_details)供Flask读取;
  • 核心逻辑:结果统计→结构化封装(字典格式)→提供读取接口;
  • 通用价值:为Flask提供统一格式的结果数据,无需Flask二次处理,可直接封装为接口响应返回给前端,提升协同效率。

2. 核心价值总结

TestRunner的核心作用是"让自动化测试执行标准化、可追溯"------通过动态加载支持多业务用例,通过生命周期管控确保流程统一,通过结构化结果提供数据支撑,是系统的"自动化执行核心"。

四、测试用例编写:通用化组件组合与实践

系统通过"基础基类+通用业务组件"的设计,支持快速编写任意业务场景的测试用例(如电商订单、金融转账、教育选课)。核心思路是"复用通用组件,仅补充业务专属逻辑",以下是通用化组件说明、用例编写流程及示例。

1. 通用化核心组件说明

通用组件 作用说明 通用化设计(不绑定具体业务)
Base 所有用例的顶层基础类,封装"日志记录、步骤存储、前置/后置步骤模板" 仅提供通用能力(如def_step定义步骤、logger输出日志),不包含任何业务逻辑,所有用例均可继承
BusinessBase 业务专属基类(继承Base),负责"业务通用初始化" 可根据业务场景扩展(如电商业务初始化"订单服务实例、商品数据库连接",金融业务初始化"转账服务、账户数据库")
ApiBase 底层接口封装类,负责"构建请求URL、发起HTTP请求、处理通用请求配置(如Cookie、超时)" 仅封装通用接口能力,不包含业务逻辑(如post/get方法、_build_url构建地址),所有业务的接口均可基于此类封装
BusinessService 业务服务组合类(依赖ApiBase),负责"将零散接口组合成业务流程+加入业务断言" 通用化业务逻辑封装(如"创建订单"="查询商品库存接口+创建订单接口+校验订单状态接口",并加入"库存足够""订单创建成功"的断言)
DataFactory 测试数据工厂,负责"生成业务所需的测试数据" 提供通用数据生成方法(如生成随机手机号、日期),同时支持业务专属数据扩展(如电商生成"订单数据",金融生成"转账金额数据")
枚举类(TestStatus/StepStatus 定义用例/步骤的标准状态(如"通过""待执行""失败") 状态值通用(如PASS="通过"PENDING="待执行"),适用于所有业务场景的状态校验

2. 通用化用例编写流程(五步完成)

无论测试何种业务(电商、金融、教育),均可按以下流程编写用例,仅需替换"业务专属组件"即可:

步骤1:选择/扩展BusinessBase(业务基类)

根据测试业务,选择已有的BusinessBase子类(如电商业务用EcommerceBase,金融业务用FinanceBase),或扩展新的业务基类(继承Base)。核心是"复用业务通用初始化逻辑",避免重复代码。
通用示例(电商业务基类)

python 复制代码
class EcommerceBase(Base):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        # 业务通用初始化:初始化商品服务、订单服务、用户Cookie
        self.goods_service = GoodsService()  # 商品业务服务(依赖ApiBase)
        self.order_service = OrderService()  # 订单业务服务(依赖ApiBase)
        self.user_cookie = kwargs.get("user_cookie")  # 从配置获取用户Cookie
        self.user_id = kwargs.get("user_id")  # 从配置获取测试用户ID
        # 初始化数据工厂(电商专属)
        self.data_factory = EcommerceDataFactory(self.goods_service, self.order_service)
步骤2:封装ApiBaseBusinessService(业务服务)
  • 第一步:基于ApiBase封装业务接口(如电商的"查询商品库存""创建订单"接口):

    python 复制代码
    class EcommerceApi(ApiBase):
        def __init__(self, base_url, cookie):
            super().__init__(base_url, cookie)  # 复用ApiBase的请求客户端、URL构建能力
        
        # 封装"查询商品库存"接口(仅发起请求,无业务逻辑)
        def get_goods_stock(self, goods_id):
            url = self._build_url(f"/api/goods/stock/{goods_id}")
            return self.client.get(url)
        
        # 封装"创建订单"接口(仅发起请求,无业务逻辑)
        def create_order(self, order_data):
            url = self._build_url("/api/order/create")
            return self.client.post(url, json=order_data)
  • 第二步:基于BusinessService组合接口+断言(形成业务流程):

    python 复制代码
    class OrderService(BusinessService):
        def __init__(self, api: EcommerceApi):
            self.api = api  # 依赖EcommerceApi
            self.logger = logging.getLogger(self.__class__.__name__)
        
        # 业务流程:创建订单(查询库存→创建订单→校验订单状态)
        def create_order_with_check(self, goods_id, user_id, buy_num):
            # 1. 第一步:查询商品库存(调用Api接口)
            stock_res = self.api.get_goods_stock(goods_id)
            if stock_res.status_code != 200:
                raise AssertionError(f"查询商品{goods_id}库存失败,状态码:{stock_res.status_code}")
            stock_num = stock_res.json()["stock"]
            # 2. 业务断言:库存足够
            if stock_num < buy_num:
                raise AssertionError(f"商品{goods_id}库存不足(当前{stock_num},需{buy_num})")
            
            # 3. 第二步:创建订单(调用Api接口)
            order_data = {"goods_id": goods_id, "user_id": user_id, "buy_num": buy_num}
            create_res = self.api.create_order(order_data)
            if create_res.status_code != 200:
                raise AssertionError(f"创建订单失败,响应:{create_res.text}")
            order_id = create_res.json()["order_id"]
            self.logger.info(f"创建订单成功,订单ID:{order_id}")
            
            # 4. 第三步:返回订单ID(供后续步骤使用)
            return order_id
步骤3:扩展DataFactory(生成业务数据)

根据业务需求,在DataFactory中添加专属数据生成方法,同一个接口可能有很多的正交数据类型,避免用例内硬编码数据:
通用示例(电商数据工厂)

python 复制代码
class EcommerceDataFactory(DataFactory):
    def __init__(self, goods_service, order_service):
        self.goods_service = goods_service
        self.order_service = order_service
    
    # 生成"合法订单数据"(依赖商品服务获取有效商品ID)
    def create_valid_order_data(self, user_id):
        # 业务逻辑:获取一个库存>0的商品ID
        valid_goods_id = self.goods_service.get_valid_goods_id()
        return {
            "goods_id": valid_goods_id,
            "user_id": user_id,
            "buy_num": self.get_random_num(1, 5),  # 通用方法:生成1-5的随机购买数量
            "pay_type": self.get_random_enum(["WECHAT", "ALIPAY"])  # 通用方法:随机选择支付方式
        }
    
    # 生成"库存不足的订单数据"(用于测试异常场景)
    def create_insufficient_stock_order_data(self, user_id):
        invalid_goods_id = self.goods_service.get_insufficient_stock_goods_id()
        return {
            "goods_id": invalid_goods_id,
            "user_id": user_id,
            "buy_num": 10,  # 购买数量大于库存
            "pay_type": "WECHAT"
        }
步骤4:编写用例类(继承BusinessBase,补充业务步骤)

用例类仅需"继承业务基类,实现defineSteps方法(定义测试步骤)",核心是"调用BusinessService的业务方法,关联DataFactory的测试数据":
通用示例(电商订单创建用例)

python 复制代码
# 1. 导入通用组件与电商业务组件
from TestRunner.core.Base import EcommerceBase, StepStatus
from services.EcommerceService import OrderService
from utils.DataFactory import EcommerceDataFactory
from utils.Enum import PayType, OrderStatus

# 2. 定义用例名称(必须,TestRunner识别用例标识)
case_name = "电商_订单创建_正常流程测试"

# 3. 编写用例类(继承电商业务基类EcommerceBase)
class test_ecommerce_order_create_normal(EcommerceBase):
    # 前置步骤:复用基类初始化,补充用例专属配置(可选)
    def setUp(self):
        super().setUp()  # 执行基类前置逻辑(初始化服务、数据工厂)
        self.target_goods_id = self.data_factory.get_valid_goods_id()  # 业务专属:获取有效商品ID
    
    # 核心:定义测试步骤(必须实现defineSteps方法)
    def defineSteps(self):
        # 步骤1:清理用户历史未支付订单(环境清理,避免影响当前测试)
        self.def_step(
            step_name="【环境清理】删除用户未支付订单",
            method=self.order_service.delete_unpaid_orders,  # 调用业务服务方法
            kwargs={"user_id": self.user_id}  # 业务参数:从基类继承的用户ID
        )
        
        # 步骤2:生成合法订单数据(调用数据工厂)
        self.def_step(
            step_name="【数据准备】生成合法订单数据",
            method=self.data_factory.create_valid_order_data,  # 调用数据工厂方法
            kwargs={"user_id": self.user_id},
            # 注意:此处可将数据工厂结果赋值给变量,供后续步骤使用
            # (TestRunner支持步骤间参数传递,需在基类中定义临时变量)
        )
        
        # 步骤3:创建订单并校验(调用业务服务,包含接口组合+断言)
        self.def_step(
            step_name="【业务执行】创建订单并校验库存、订单状态",
            method=self.order_service.create_order_with_check,  # 调用业务服务的核心方法
            kwargs={
                "goods_id": self.target_goods_id,
                "user_id": self.user_id,
                "buy_num": 2  # 购买数量(可从数据工厂获取,此处简化示例)
            }
        )
        
        # 步骤4:校验订单状态为"待支付"(调用业务服务的校验方法)
        self.def_step(
            step_name="【状态校验】订单状态为待支付",
            method=self.order_service.check_order_status,  # 业务校验方法
            kwargs={
                "order_id": self.order_service.last_order_id,  # 步骤3返回的订单ID(业务服务存储)
                "expected_status": OrderStatus.UNPAID.value  # 通用枚举:待支付状态
            }
        )
    
    # 后置步骤:清理测试数据(可选)
    def tearDown(self):
        super().tearDown()  # 执行基类后置逻辑(基础日志)
        # 业务专属清理:删除当前用例创建的订单
        self.order_service.delete_order(self.order_service.last_order_id)
        self.logger.info(f"===== 用例{case_name}执行完成,已清理测试数据 =====")
步骤5:配置用例路径,接入系统执行

将编写好的用例脚本放在指定目录(如test_cases/ecommerce/),在Flask的配置中添加"业务类型-用例路径"映射通过Flask接口触发执行。

3. 新业务用例编写总结(通用化思路)

无论新增何种业务的测试用例,均可遵循以下通用步骤,实现快速接入:

  1. 搭业务基类 :继承Base类,实现"业务通用初始化"(如服务实例、数据库连接、用户配置);
  2. 封接口与服务 :基于ApiBase封装业务接口,基于BusinessService组合接口成业务流程+断言;
  3. 造测试数据 :扩展DataFactory,生成业务所需的"正常数据""异常数据";
  4. 写用例步骤 :继承业务基类,在defineSteps中调用"业务服务方法+数据工厂",定义测试步骤;
  5. 配路径执行:将用例放在指定目录,配置"业务类型-用例路径"映射,通过Flask接口触发。

五、系统整体价值与扩展建议

1. 整体价值

  • 通用化适配:不绑定具体业务,可快速接入电商、金融、教育等各类业务的自动化测试需求;
  • 低代码编写:复用通用组件,编写新用例仅需补充业务专属逻辑,降低测试人员技术门槛;
  • 全流程可控:从"发起请求→执行测试→查询结果"全流程可监控、可追溯,便于团队协作;
  • 工具链集成:通过Flask标准化接口,可无缝接入CI/CD流水线、测试平台,推动自动化测试融入研发流程。

2. 扩展建议

  • 接口层扩展:新增"任务取消""结果导出(Excel/PDF)"接口,提升用户体验;
  • 执行层扩展:TestRunner支持"用例优先级""并发控制",适配大规模用例执行场景;
  • 监控层扩展:新增"执行告警"功能(如用例失败时发送邮件/钉钉通知),提升问题响应速度。
相关推荐
Apifox11 小时前
Apifox 8 月更新|新增测试用例、支持自定义请求示例代码、提升导入/导出 OpenAPI/Swagger 数据的兼容性
前端·后端·测试
三翼鸟数字化技术团队1 天前
AI应用--接口测试篇
测试
郝同学的测开笔记1 天前
打通回家之路:OpenVPN,你的企业网络万能钥匙(一)
运维·后端·测试
前端工作日常2 天前
我的 Weex 测试 入门之旅
前端·测试
前端工作日常2 天前
我的 端到端(E2E)测试 入门之旅
前端·测试
前端工作日常2 天前
我的 代码覆盖率 入门之旅
前端·测试
前端工作日常2 天前
我的 单元测试 入门之旅
前端·测试
一枚前端小能手3 天前
🧪 改个代码就出Bug的恐惧,前端测试来帮忙
前端·测试
小张同学zkf3 天前
【测试】基于博客系统的测试报告
python·功能测试·压力测试·测试