测试老鸟,带你手写Python自动化测试 ddt 数据驱动框架(超细细)

news2024/11/8 9:41:17

前言

python做自动化测试,大多数都应该使用过ddt这个模块,它可以自动根据用例数据,来生成测试用例,能够很方便的将测试数据和测试用例执行的逻辑进行分离。接下来和大家,手把手撸出一个ddt。

DDT的实现原理

首先我们来看一下ddt的基本使用:

@ddt
class TestLogin(unittest.TestCase):
	
	@data(*Cases)
	def test_login__pass(self,item):

ddt在使用时非常简洁,也就是两个装饰器,@ddt这个装饰器装饰测试类,@data这个装饰器装饰器用例方法并传入测试数据。

这两个装饰器实现的效果就是根据传入的用例数据自动生成用例。具体是怎么实现的呢?

其实实现的思路也特别的简单,也就两个步骤:
第一步:把传进来的用例数据保存起来
第二步:遍历用例数据,每遍历一条数据 就动态的给测试类添加一个用例方法。

ddt中的两个装饰器其实实现的就是这么两个步骤:
@data:做的是第一步将传入测试数据保存起来;
@ddt做的是第二步,遍历用例数据,给测试类动态添加用例方法。

data装饰器的实现

前面我们说到data这个装饰器,做的事情是将用例数据保存起来。那么如何保存呢?其实最简单的方式就是 保存被装饰的这个用例方法的属性。接下来我们来具体实现:

先看一个ddt使用的案例

@ddt
class TestLogin(unittest.TestCase):

    @data(11,22)
    def test_login(self, item):
    	pass

了解过装饰器装饰器原理的小伙伴,应该都知道上面@data(11,22) 这行代码执行的效果等同于

test_login = data(11,22)(test_login)

接下来我们来分析一下上面这行代码,首先是调用data这个装饰器函数,把用例数据11,22当成参数传入进去,然后返回一个可调用对象(函数),再次调用返回的函数并把用例方法传入进去。明确了调用的流程那么我们就可以结合之前的需求去定义data这个装饰器函数了。

具体实现如下:

def data(*args):
    def wrapper(func):
        setattr(func, "PARAMS", args)
        return func
    return wrapper

代码解读:
前面的案例在使用data时,执行的test_login = data(11,22)(test_login)
先调用data传入的11,22 通过不定长参数args接收,然后返回嵌套的函数wrapper
然后调用返回的wrapper函数,传入被装饰的test_login方法
在wrapper函数中我们把用例数据保存为test_login这个方法的PARAMS属性,再把test_login返回,到此为止,data这个装饰器我们就实现用例数据的保存

ddt装饰器的实现

通过data这个装饰器我们实现了用例数据保存之后,我们接下来实现ddt这个装饰器,根据用例数据生成测试用例。前面的案例 @ddt装饰测试类的时候,实际上执行的效果等同于下面的代码

TestLogin = ddt(TestLogin)

这行代码就是把被装饰器的类传入到ddt这个装饰器函数中,再把返回值赋值给TestLogin。之前我们分析的时候说了ddt这个装饰器做的事情是遍历用例数据,动态的给测试类添加用例方法,接下来我们就来实现ddt这个装饰器内部的逻辑。

def ddt(cls):
    for name, func in list(cls.__dict__.items()):
        if hasattr(func, "PARAMS"):
            for index, case_data in enumerate(getattr(func, "PARAMS")):
                new_test_name ="{}_{}".format(name,index)
                setattr(cls, new_test_name, func)
            else:
                delattr(cls, name)
    return cls

代码解读:

ddt函数内部逻辑说明:
调用ddt这个函数时会把测试类当成参数传入进来;
然后通过cls.__dict__获取测试的所有属性和方法,进行遍历;
判断遍历出来的属性或方法 有没有PARAMS这个属性;
如果有,则说明这个方法用data装饰器装饰过并传入了用例数据;
通过getattr(func, “PARAMS”)获取所有的用例数据,进行遍历;
每遍历出来一组用例数据,生产一个用例方法名, 再动态的给测试类添加一个用例方法;
遍历完所有用例数据之后,删除测试类原来定义的测试方法;
最后返回测试类;

当目前为止ddt和data这两个装饰器函数的基本功能实现了,可以自动根据用例数据生成测试用例了,接下来我们写个测试类来检查一下

# 定义装饰器函数data
def data(*args):
    def wrapper(func):
        setattr(func, "PARAMS", args)
        return func

    return wrapper

# 定义装饰器函数ddt
def ddt(cls):
    for name, func in list(cls.__dict__.items()):
        if hasattr(func, "PARAMS"):
            for index, case_data in enumerate(getattr(func, "PARAMS")):
                new_test_name = "{}_{}".format(name, index)
                setattr(cls, new_test_name, func)
            else:
                delattr(cls, name)
    return cls


import unittest

# 编写测试类
@ddt
class TestDome(unittest.TestCase):
    @data(11, 22, 33, 44)
    def test_demo(self):
        pass

运行上述用例,我们就会发现执行了四条用例,根据用例数据生成用例的功能就已经实现了。

用例参数传递的问题

虽然上面基本的功能已经实现了,但是还存在一个问题。用例的数据没有传递到用例方法中。那么用例数据传递怎么实现了,我们可以通过一个闭包函数对用例方法进行修,从而实现在调用用例方法的时候,把用例测试当成参数传递进去。修改原有用例方法的函数代码如下

from functools import wraps

def update_test_func(test_func,case_data):
    @wraps(test_func)
    def wrapper(self):
        return test_func(self, case_data)
    return wrapper

代码解读:
上面我们定义了一个叫做update_test_func的闭包函数
闭包函数接收两个参数:test_func(接收用例方法),case_data(接收用例数据)
闭包函数返回一个嵌套函数,嵌套函数内部调用原来的用例方法,并传入测试数据
嵌套函数在定义时,使用了functools模块中的装饰器wraps来装饰,它可以让wrapper这个嵌套函数具有test_func这个用例函数的相关属性。

下面我们回到前面写的ddt这个函数中,在给测试类添加用例之前,调用update_test_func方法对用例方法进行修改。

def ddt(cls):
    for name, func in list(cls.__dict__.items()):
        if hasattr(func, "PARAMS"):
            for index, case_data in enumerate(getattr(func, "PARAMS")):
                # 生成一个用例方法名
                new_test_name = "{}_{}".format(name, index)
                # 修改原有的测试方法,设置用例数据为测试方法的参数
                test_func = update_test_func(func,case_data)
                setattr(cls, new_test_name, test_func)
            else:
                delattr(cls, name)
    return cls

通过加上这一步之后,我们在测试类中 动态给测试类添加的测试方法,其实指向的全部是update_test_func里面定义的wrapper函数,在执行测试用的时候实际上也是执行的wrapper函数,而在wrapper函数内部,我们调用了原来定义的测试方法,并将用例数据传入了进去,到此为止ddt的功能我们就完全实现了。

完整代码

from functools import wraps
import unittest

# --------ddt的实现--------
def data(*args):
    def wrapper(func):
        setattr(func, "PARAMS", args)
        return func

    return wrapper


def update_test_func(test_func, case_data):
    @wraps(test_func)
    def wrapper(self):
        return test_func(self, case_data)

    return wrapper


def ddt(cls):
    for name, func in list(cls.__dict__.items()):
        if hasattr(func, "PARAMS"):
            for index, case_data in enumerate(getattr(func, "PARAMS")):
                # 生成一个用例方法名
                new_test_name = "{}_{}".format(name, index)
                # 修改原有的测试方法,设置用例数据为测试方法的参数
                test_func = update_test_func(func, case_data)
                setattr(cls, new_test_name, test_func)
            else:
                delattr(cls, name)
    return cls

# --------测试用例编写--------
@ddt
class TestDome(unittest.TestCase):
    @data(11, 22, 33, 44)
    def test_demo(self, data):
        assert data < 40
		
#---------用例执行-----------
unittest.main()

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

【软件测试技术交流(资料分享)】:320231853(备注C)icon-default.png?t=N5K3http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=rS49sB1dBN6wjk4SbxAjX80YS65Zy8TH&authKey=tlP2KE7Sut5Dq7EvwkG55B%2B0sWc5WpLYbuRGFftTLHed0FB22lskhUs4Dnw6hQRP&noverify=0&group_code=320231853

生命不息,奋斗不止。每一份努力都不会被辜负,只要坚持不懈,终究会有回报。珍惜时间,追求梦想。不忘初心,砥砺前行。你的未来,由你掌握!

生命短暂,时间宝贵,我们无法预知未来会发生什么,但我们可以掌握当下。珍惜每一天,努力奋斗,让自己变得更加强大和优秀。坚定信念,执着追求,成功终将属于你!

只有不断地挑战自己,才能不断地超越自己。坚持追求梦想,勇敢前行,你就会发现奋斗的过程是如此美好而值得。相信自己,你一定可以做到!

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

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

相关文章

MUR80120PT-ASEMI快恢复二极管MUR80120PT

编辑-Z MUR80120PT在TO-247封装里采用的2个芯片&#xff0c;其尺寸都是140MIL&#xff0c;是一款高耐压大电流快恢复二极管。MUR80120PT的浪涌电流Ifsm为600A&#xff0c;漏电流(Ir)为10uA&#xff0c;其工作时耐温度范围为-55~150摄氏度。MUR80120PT采用抗冲击硅芯片材质&…

DJ5-4 MAC、ARP

目录 一、链路层寻址地址 1、MAC 地址分配 2、MAC 地址识别 二、ARP 地址解析协议 1、ARP 地址解析协议 2、ARP&#xff1a;两个主机位于同一个局域网 3、ARP&#xff1a;发送数据报到子网以外 4、ARP 自举 5、ARP 攻击 一、链路层寻址地址 每个节点有网络层地址和链…

模拟电路系列分享-静态工作点

文章目录 概要整体架构流程技术名词解释技术细节小结 概要 提示&#xff1a;这里可以添加技术概要 例如&#xff1a; 本文主要介绍静态工作点及耦合 整体架构流程 提示&#xff1a;这里可以添加技术整体架构 要想让晶体管对输入电压信号进行有效的放大&#xff0c;必须解…

win10安装配置PostgreSQL

win10安装配置PostgreSQL 1 下载安装PostgreSQL ①进入官网https://www.postgresql.org/&#xff0c;点击页面中心处的download 也可以直接跳过下面的步骤(下面的步骤主要是为了帮助大家了解一般外国软件是如何从官网进入下载页面)&#xff0c;直接进入下载页面&#xff0c;链…

网络安全是个好的专业吗?高考志愿可以选择该专业吗?

首先说说关于学校和就业的问题&#xff0c;提到国内网络安全专业比较好的学校&#xff0c;“四邮四电”&#xff08;北邮、南邮、西邮、重邮、电子科大、西安电子科大、桂林电子科大、杭州电子科大&#xff09;必须拥有姓名。 而从现在的就业形势看&#xff0c;网络安全专业其…

SuperMap GIS基础产品三维GIS FAQ集锦(3)

SuperMap GIS基础产品三维GIS FAQ集锦&#xff08;3&#xff09; 【WebGL】如何批量管理entity图标&#xff0c;同时控制多个图标的显示和隐藏&#xff1f; 【解决办法】使用实体集合CustomDataSource进行管理&#xff0c;将实体按类别分类&#xff0c;分别添加到不同的实体集…

数字 IC 设计职位经典笔/面试题(一)

共100道经典笔试、面试题目&#xff08;文末可全领&#xff09; 什么是同步逻辑和异步逻辑&#xff1f; 同步逻辑是时钟之间有固定的因果关系。异步逻辑是各时钟之间没有固定的因果关系。同步时序逻辑电路的特点&#xff1a;各触发器的时钟端全部连接在一起&#xff0c;并接在…

NAPT之NAT地址池、NAPT之easy-ip、NAT-Server

NAPT之NAT地址池 拓扑 需求 实现企业内网主机&#xff08;PC1-PC4&#xff09;访问公网网站服务器&#xff08;Server1&#xff09; 配置步骤 第一步&#xff1a;给PC1-PC4/Server1配置接口IP地址&#xff0c;掩码&#xff0c;网关 第二步&#xff1a;R1配置默认路由 -边界…

【MySql】用户管理——用户管理|权限管理

文章目录 用户管理用户信息创建用户删除用户修改用户密码 数据库的权限给用户授权回收权限 用户管理 如果我们只能使用root用户&#xff0c;这样存在安全隐患。这时&#xff0c;就需要使用MySQL的用户管理。 比如张三只能操作mytest这个数据库&#xff0c;李四只能操作msg这个…

员工身份管理(EIAM)如何帮助企业降本增效?

随着市场竞争的加剧和经济环境的变化&#xff0c;降本增效成为了现代企业的共同目标。要实现这一目标&#xff0c;企业需要彻底改变传统的生产管理方式&#xff0c;借助数字化技术来实现数据在线、人员在线和行为在线。 数据在线意味着企业的数据可以在多个平台上进行共享、协…

FreeRTOS实时操作系统(七)时间片调度及RTOS的滴答定时器

系列文章目录 FreeRTOS实时操作系统&#xff08;一&#xff09;RTOS的基本概念 FreeRTOS实时操作系统&#xff08;二&#xff09;任务创建与任务删除&#xff08;HAL库&#xff09; FreeRTOS实时操作系统&#xff08;三&#xff09;任务挂起与恢复 FreeRTOS实时操作系统&am…

【Linux】硬件性能测试工具

1、CPU 1.1 stress 1)安装 sudo apt install stress 2)用法 stress --cpu 8 --io 4 --vm 2 --vm-bytes 128M --timeout 60s3)结果 使用htop查看: 1.2 nbench 1)安装 需要源码编译,源码下载地址 官方(下载很慢):https://www.math.utah.edu/~mayer/linux/bmark.ht…

数据产品-完善DMP系统应该是什么样子的

一、价值定位 首先需要明确DMP系统的价值定位和核心功能&#xff0c;以此才能评估需要涵括哪些内容 ✧用户刻画更清晰&#xff1a;能够通过数据标签化的形式&#xff0c;全面、精准刻画用户全貌 ✧用户触达更精准&#xff1a;能够沉淀不同的策略规则&#xff0c;精准触达不同…

转行做TA(技术美术),需要掌握哪些基础知识?

TA的岗位职责 负责美术与程序之间的沟通&#xff0c;配合实现美术效果&#xff0c;提高画面整体表现力制定美术资源规范&#xff0c;提高导出资源的可用性和规范性快速跟进研发最新的游戏引擎与渲染技术&#xff1b;在性能优化的同时&#xff0c;提高游戏画面表现&#xff1b;…

2023年6月墨天轮中国图数据库排行榜:TGS 开新局,创邻和字节多点突破露锋芒

鸿鹄不坠青云志&#xff0c;鲲鹏展翅九万里。 2023年 墨天轮中国图数据库流行度排行 已经火热出炉&#xff0c;本月中国图数据库排行榜共有31个数据库参与排名&#xff0c;相比今年1月新增3个数据库。本月图数据库榜单前十变动较大&#xff1a;TuGraph 立足创新跃榜首&#xff…

深蓝学院C++基础与深度解析笔记 第 6 章 函数

1. 函数基础 ● 函数&#xff1a;封装了一段代码&#xff0c;可以在一次执行过程中被反复调用。 A、函数头&#xff1a; ● 函数名称 —— 标识符&#xff0c;用于后续的调用 ● 形式参数 —— 代表函数的输入参数 ● 返回类型 —— 函数执行完成后所返回的结果类型 B、函数…

Matplotlib---雷达图

1. 雷达图 fig plt.figure(figsize(6, 6))x np. linspace(0, 2*np.pi, 6, endpointFalse) y [83, 61, 95, 67, 76, 88]# 保证首位相连 x np.concatenate((x, [x[0]])) y np.concatenate((y, [y[0]]))# 雷达图 axes plt.subplot(111, polarTrue) axes.plot(x, y, o-, l…

记录正式环境测试环境【RedHat7编译升级redis7.0.9】--有关报错及解决

记录正式环境&测试环境【RedHat7 编译升级redis7.0.9】--有关报错及解决 &#x1f53b; 一、报错详情1.1 ⛳ 写在前面1.2 ⛳ 报错11.3 ⛳ 报错21.4 ⛳ 安装redis1.5 ⛳ 版本检查 &#x1f53b; 二、⛳ 总结 &#x1f53b; 一、报错详情 1.1 ⛳ 写在前面 &#x1f341; 升级…

甘特图神器大比拼——国内外7款经典工具评测

甘特图是一种重要的项目管理工具&#xff0c;它能够帮助我们规划、安排和跟踪项目的进度和任务。然而&#xff0c;市面上的甘特图工具众多&#xff0c;选择恰当的工具并不容易。在本文中&#xff0c;我们将为您介绍国内外7款经典的甘特图神器&#xff0c;并进行详细评测和比较。…

常见分布式事务

一、2PC 将事务的提交过程分为 资源准备 和 资源提交 两个阶段&#xff0c;准备阶段所有事务参与者都预留资源的成功与否&#xff0c;决定了第二阶段提交或回滚。 2PC 第一阶段&#xff1a;准备阶段 1.协调者向所有参与者发送事务内容&#xff0c;询问是否可以提交事务&#…