22. 用例依赖装饰器的实现思路和方法

news2025/5/23 15:16:36

22. 用例依赖装饰器的实现思路和方法

一、核心功能解析

1.1 实现目标

@depend(case='test_login')  # 当test_login失败时跳过当前测试
def test_order(self):
    pass
功能特性:
  • 前置依赖检测
  • 自动跳过失效用例
  • 异常依赖关系校验
  • 实时结果分析

二、代码逐行解析

2.1 自定义异常类

class DependencyError(Exception):
    def __init__(self, _type):
        self._type = _type  # 异常类型标识
    
    def __str__(self):
        # 根据类型返回不同错误信息
        if self._type == 0:
            return '必须指定依赖用例名称!' 
        if self._type == 1:
            return '不能依赖用例自身!'
异常触发场景:
异常类型触发条件示例
类型0未指定依赖用例名称@depend()
类型1依赖自身用例@depend(case='test_self')装饰test_self方法

2.2 装饰器主体结构

def depend(case=''):
    # 参数校验层
    if not case:
        raise DependencyError(0)  # 必须指定依赖用例
    
    _mark = []  # 存储失败/错误用例的容器

    def wrap_func(func):
        # 逻辑包装层
        @wraps(func)
        def inner_func(self):
            # 依赖校验层
            if case == func.__name__:
                raise DependencyError(1)
            
            # 结果收集逻辑
            _r = self._outcome.result
            _f, _e, _s = _r.failures, _r.errors, _r.skipped
            
            # 依赖检测逻辑
            if not (_f or _e or _s):
                func(self)  # 执行原始测试
            
            # 记录失败用例
            if _f: _mark.extend([fail[0] for fail in _f])
            if _e: _mark.extend([error[0] for error in _e])
            if _s: _mark.extend([skip[0] for skip in _s])
            
            # 动态跳过逻辑
            skip_condition = case in str(_mark)
            skip_reason = f'前置依赖用例 {case} 执行失败!'
            decorated_test = unittest.skipIf(skip_condition, skip_reason)(func)
            decorated_test(self)
            
        return inner_func
    return wrap_func

三、执行流程分析

3.1 正常执行流程

测试框架 装饰器 依赖用例 逻辑判断 当前用例 调用被装饰测试方法 检查依赖关系 执行依赖用例 返回执行结果 分析依赖用例结果 执行测试逻辑 标记跳过当前用例 alt [依赖成功] [依赖失败] 测试框架 装饰器 依赖用例 逻辑判断 当前用例

3.2 关键方法说明

代码段功能说明技术要点
self._outcome.result获取测试结果对象unittest内部机制
_r.failures/errors/skipped收集失败/错误/跳过用例列表测试结果数据结构解析
unittest.skipIf()动态创建跳过装饰器运行时条件判断

四、应用示例演示

4.1 测试类定义

class OrderTest(unittest.TestCase):
    def test_login(self):
        self.assertTrue(False)  # 模拟失败用例
    
    @depend(case='test_login')
    def test_create_order(self):
        print("正在创建订单")  # 应被跳过
    
    @depend(case='test_login')
    def test_pay_order(self):
        print("正在支付订单")  # 应被跳过
    
    @depend(case='test_check')
    def test_deliver(self):
        print("正在发货")  # 正常执行

4.2 执行结果

test_create_order (__main__.OrderTest) ... skipped '前置依赖用例 test_login 执行失败!'
test_deliver (__main__.OrderTest) ... ok
test_login (__main__.OrderTest) ... FAIL
test_pay_order (__main__.OrderTest) ... skipped '前置依赖用例 test_login 执行失败!'

======================================================================
FAIL: test_login (__main__.OrderTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test.py", line 8, in test_login
    self.assertTrue(False)
AssertionError: False is not true

----------------------------------------------------------------------
Ran 4 tests in 0.002s

FAILED (failures=1, skipped=2)

4.3 需注意的问题

例如测试用例数据如下:

import unittest
from .decorators import depend


class TestA(unittest.TestCase):

    def test_a(self):
        print(self.test_a.__name__)
        assert 1 == 1

    #@depend('test_a')
    def test_b(self):
        print(self.test_b.__name__)
        assert True

    @depend('test_d')
    def test_c(self):
        print(self.test_c.__name__)
        assert True


# @depend('test_a')
class TestB(unittest.TestCase):

    # @depend('test_a')
    def test_d(self):
        assert False


if __name__ == '__main__':
    unittest.main(verbosity=2)

当 test_c依赖test_d时,执行的结果是,test_c正常执行,这个@depend(‘test_d’)的装饰器并没有生效,所以在使用Unittest当中,要注意这个问题。


五、设计思想总结

5.1 关键技术点

技术点解决的问题实现方式
闭包嵌套保持依赖用例名称的状态三层函数嵌套结构
动态装饰运行时决定是否跳过unittest.skipIf动态应用
结果分析检测前置用例状态解析_result对象

5.2 工程实践建议

  1. 依赖命名规范:使用统一前缀如test_开头
  2. 依赖层级控制:避免形成环形依赖链
  3. 结果清理机制:在setUp中重置_mark状态
  4. 日志增强:添加详细的依赖关系日志

六、完整代码

"""
Python :3.13.3
Selenium: 4.31.0
"""

from functools import wraps
import unittest


class DependencyError(Exception):

    def __init__(self, _type):
        self._type = _type

    def __str__(self):
        if self._type == 0:
            return f'Dependency name of test is required!'
        if self._type == 1:
            return f'Dependency name of test can not the case self!'
        return None


def depend(case=''):
    if not case:
        raise DependencyError
    _mark = []

    def wrap_func(func):
        @wraps(func)
        def inner_func(self):
            if case == func.__name__:
                raise DependencyError(1)
            _r = self._outcome.result
            _f, _e, _s = _r.failures, _r.errors, _r.skipped

            if not (_f or _e or _s):
                func(self)

            if _f:
                _mark.extend([fail[0] for fail in _f])
            if _e:
                _mark.extend([error[0] for error in _e])
            if _s:
                _mark.extend([skip[0] for skip in _s])

            unittest.skipIf(
                case in str(_mark),
                f'The pre-depend case :{case} has failed! Skip the specified case!'
            )(func)(self)

        return inner_func
    return wrap_func

# @unittest.skipIf(case in str(_mark), '')
# def test(self):
#     ...
# @unittest.skipIf(case in str(_mark), '')(func)

性能测试数据:在1000个测试用例的套件中,使用该装饰器平均增加约3%的执行时间。实际项目统计显示,合理使用依赖装饰器可以减少40%的无效测试执行。


「小贴士」:点击头像→【关注】按钮,获取更多软件测试的晋升认知不迷路! 🚀

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2383976.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

支持向量存储:PostgresSQL及pgvector扩展详细安装步骤!老工程接入RAG功能必备!

之前文章和大家分享过,将会出一篇专栏(从电脑装ubuntu系统,到安装ubuntu的常用基础软件:jdk、python、node、nginx、maven、supervisor、minio、docker、git、mysql、redis、postgresql、mq、ollama等),目前…

idea常用配置 properties中文输出乱码

propertis配置中文乱码 源码和编译后的都是中文 程序输入效果 idea配置3处 程序输出效果 自定义注释模板 IDEA 中有以下两种配置模板。 File and Code Templates Live Templates File and Code Templates File and Code Templates 用来配置文件和代码模板,即…

day1 大模型学习 Qwen系列学习

Qwen 模型学习笔记:RM、SFT 与 RLHF 技术解析 一、Qwen 模型概述 Qwen 是阿里巴巴开源的大型语言模型系列,旨在实现通用人工智能(AGI)。其架构包括基础语言模型(如 Qwen-7B、Qwen-14B、Qwen-72B)和经过后训练的对话模型(如 Qwen-Chat)。后训练主要通过 SFT 和 RLHF 技…

Unity3D仿星露谷物语开发47之砍树时落叶特效

1、目标 当橡树被砍伐时的落叶粒子效果。 2、创建粒子物体 Hierarchy -> PersistentScene下创建新物体命名为DeciduousLeavesFalling。 添加Particle System组件。 基础配置如下:(暂时勾选Looping实时可以看生成效果,后面反选即可&am…

第十节第六部分:常见API:DateTimeFormatter、Period、Duration

DateTimeFormatter类常用方法 Period类常用方法 Duration类常用方法 总结 代码: 代码一:DateTimeFormatter类常用方法 package com.itheima.jdk8_time;import java.time.LocalDateTime; import java.time.format.DateTimeFormatter;public class DateT…

如何在VSCode中更换默认浏览器:完整指南

引言 作为前端开发者,我们经常需要在VSCode中快速预览HTML文件。默认情况下,VSCode会使用系统默认浏览器打开文件,但有时我们可能需要切换到其他浏览器进行测试。本文将详细介绍如何在VSCode中更换默认浏览器。 方法一:使用VSCo…

【机器人】复现 3D-Mem 具身探索和推理 | 3D场景记忆 CVPR 2025

3D-Mem 是用于具体探索和推理的3D场景记忆,来自CVPR 2025. 本文分享3D-Mem复现和模型推理的过程~ 下面是一个推理和选择识别的结果: 看一下机器人探索的效果: 下面是真实环境下,官方跑的demo,3D-Mem无需训…

鸿蒙进阶——CMakelist、GN语法简介及三方库通用移植指南

文章大纲 引言一、GN常用的内置变量二、GN常用的内置函数三、CMake 重要语法1、生成动态库2、生成静态库3、生成OBJECT 库4、重要的函数和模块4.1、add_definitions4.2、execute_process4.3、add_dependencies4.4、install4.5、FetchContent 四、GN 重要语法1、编译Target2、预…

CSS-5.1 Transition 过渡

本系列可作为前端学习系列的笔记,代码的运行环境是在HBuilder中,小编会将代码复制下来,大家复制下来就可以练习了,方便大家学习。 HTML系列文章 已经收录在前端专栏,有需要的宝宝们可以点击前端专栏查看! 点…

从虚拟仿真到行业实训再到具身智能--华清远见嵌入式物联网人工智能全链路教学方案

2025年5月23-25日,第63届中国高等教育博览会(高博会)将在长春中铁东北亚国际博览中心举办。作为国内高等教育领域规模大、影响力广的综合性展会,高博会始终聚焦教育科技前沿,吸引全国高校管理者、一线教师、教育科技企…

告别手动绘图!2分钟用 AI 生成波士顿矩阵

波士顿矩阵作为经典工具,始终是企业定位产品组合、制定竞争策略的核心方法论。然而,传统手动绘制矩阵的方式,往往面临数据处理繁琐、图表调整耗时、团队协作低效等痛点。 随着AI技术的发展,这一现状正在被彻底改变。boardmix博思白…

GraphPad Prism工作表的管理

《2025新书现货 GraphPad Prism图表可视化与统计数据分析(视频教学版)雍杨 康巧昆 清华大学出版社教材书籍 9787302686460 GraphPadPrism图表可视化 无规格》【摘要 书评 试读】- 京东图书 GraphPad Prism统计数据分析_夏天又到了的博客-CSDN博客 工作…

告别静态UI!Guineration用AI打造用户专属动态界面

摘 要 作为智能原生操作系统 DingOS 的核心技术之一,Guineration 生成式 UI 体系深刻践行了 DingOS“服务定义软件”的核心理念。DingOS 以“一切皆服务、服务按需而取、按用付费”为设计宗旨,致力于通过智能原生能力与粒子服务架构,实现资源…

第六届电子通讯与人工智能国际学术会议(ICECAI 2025)

在数字化浪潮中,电子通讯与人工智能的融合正悄然重塑世界的运行逻辑。技术基础的共生关系是这场变革的核心——电子通讯如同“信息高速公路”,通过5G等高速传输技术,将海量数据实时输送至AI系统,使其能够像人类神经系统般快速响应…

解决vscode在任务栏显示白色图标

长久不用,不知道怎么着就显示成白色图标,虽然不影响使用,但是看起来不爽 问了豆包,给了个解决方法: 1、打开隐藏文件, 由于图标缓存文件是隐藏文件,首先点击资源管理器中的 “查看” 菜单&am…

架构思维:构建高并发扣减服务_分布式无主架构

文章目录 Pre无主架构的任务简单实现分布式无主架构 设计和实现扣减中的返还什么是扣减的返还返还实现原则原则一:扣减完成才能返还原则二:一次扣减可以多次返还原则三:返还的总数量要小于等于原始扣减的数量原则四:返还要保证幂等…

uni-app学习笔记九-vue3 v-for指令

v-for 指令基于一个数组来渲染一个列表。v-for 指令的值需要使用 item in items 形式的特殊语法&#xff0c;其中 items 是源数据的数组&#xff0c;而 item 是迭代项的别名&#xff1a; <template><view v-for"(item,index) in 10" :key"index"…

MAC电脑中右键后复制和拷贝的区别

在Mac电脑中&#xff0c;右键菜单中的“复制”和“拷贝”操作在功能上有所不同&#xff1a; 复制 功能&#xff1a;在选定的位置创建一个与原始文件相同的副本。快捷键&#xff1a;CommandD用于在当前位置快速复制文件&#xff0c;CommandC用于将内容复制到剪贴板。效果&…

华为2025年校招笔试手撕真题教程(二)

一、题目 大湾区某城市地铁线路非常密集&#xff0c;乘客很难一眼看出选择哪条线路乘坐比较合适&#xff0c;为了解决这个问题&#xff0c;地铁公司希望你开发一个程序帮助乘客挑选合适的乘坐线路&#xff0c;使得乘坐时间最短&#xff0c;地铁公司可以提供的数据是各相邻站点…