数据驱动测试-从方法探研到最佳实践

news2024/11/28 2:55:04

作者:刘红妍

导读

在自动化测试实践中,测试数据是制造测试场景的必要条件,本文主要讲述了在沟通自动化框架如何分层,数据如何存储,以及基于单元测试pytest下如何执行。并通过实践案例分享,提供数据驱动测试的具体落地方案。

基本概念

数据驱动测试(DDT)是一种方法,其中在数据源的帮助下重复执行相同顺序的测试步骤,以便在验证步骤进行时驱动那些步骤的输入值和/或期望值。在数据驱动测试的情况下,环境设置和控制不是硬编码的。换句话说,数据驱动的测试是在框架中构建要与所有相关数据集一起执行的测试脚本,该脚本利用了可重用的测试逻辑。数据驱动的测试提供了可重复性,将测试逻辑与测试数据分离以及减少测试用例数量等优势。

 设计思路

2.1 测试数据

在测试过程中往往需要更加充分地测试场景,而创建数据测试。测试数据包括输入输出,对输出的自动化验证等。创建测试数据,可以通过手动拼装,生产环境拷贝,或通过自动化工具生成。

2.2 数据存储

数据驱动测试中使用的数据源可以是Excel文件,CSV文件,Yaml文件,数据池,ADO对象或ODBC源。

2.3 数据驱动优势

1. 如果应用程序开发还在进行当中,测试者仍然可以进行脚本的编写工作。

2. 减少了冗余和不必要的测试脚本。

3. 用较少的代码生成测试脚本。

4. 所有信息,如输入、输出和预期结果,都以适当的文本记录形式进行存储。

5. 为应用程序的维护提供利了灵活性条件。

6. 如果功能发生了变化,只需要调整特定的函数脚本。

 实践分享

基于Laputa框架现有测试脚本,抽离测试数据与测试逻辑,实现数据驱动测试。

Laputa框架简介:Laputa框架基于 Pytest 集成了对API接口自动化, 以及对 Web应用, 移动端应用和 Windows 桌面应用 UI 等自动化的能力。具有可视化的Web界面工具, 便于配置执行规则,关联执行脚本, 触发用例执行,查看执行结果。提供CI集成服务,调用Jenkins API跟踪持续集成结果,开放接口,实现流水线自动化测试。

3.1 环境依赖

3.2.1 参数化配置方式

pytest参数化有两种方式:

@pytest.fixture(params=[])

@pytest.mark.parametrize()

两者都会多次执行使用它的测试函数,但@pytest.mark.parametrize()使用方法更丰富一些,laputa更建议使用后者。

3.2.2 用 parametrize 实现参数化

parametrize( ) 方法源码:

【python】
def parametrize(self,argnames, argvalues, indirect=False, ids=None, scope=None):

1. 主要参数说明

(1)argsnames :参数名,是个字符串,如中间用逗号分隔则表示为多个参数名。

(2)argsvalues :参数值,参数组成的列表,列表中有几个元素,就会生成几条用例。

2. 使用方法

(1)使用 @pytest.mark.paramtrize() 装饰测试方法;

(2)parametrize('data', param) 中的 “data” 是自定义的参数名,param 是引入的参数列表;

(3)将自定义的参数名 data 作为参数传给测试用例 test_func;

(4)在测试用例内部使用 data 的参数。

创建测试用例,传入三组参数,每组两个元素,判断每组参数里面表达式和值是否相等,代码如下:

【python】
@pytest.mark.parametrize("test_input,expected",[("3+5",8),("2+5",7),("7*5",30)])
def test_eval(test_input,expected):
    # eval 将字符串str当成有效的表达式来求值,并返回结果
    assert eval(test_input) == expected

运行结果:

【python】

test_mark_paramize.py::test_eval[3+5-8]test_mark_paramize.py::test_eval[2+5-7] 

test_mark_paramize.py::test_eval[7*5-35]




============================== 3 passed in 0.02s ===============================

整个执行过程中,pytest 将参数列表 ("3+5",8),("2+5",7),("7*5",30) 中的三组数据取出来,每组数据生成一条测试用例,并且将每组数据中的两个元素分别赋值到方法中,作为测试方法的参数由测试用例使用。

3.2.3 多次使用 parametrize

同一个测试用例还可以同时添加多个 @pytest.mark.parametrize 装饰器, 多个 parametrize 的所有元素互相组合(类似笛卡儿乘积),生成大量测试用例。

场景:比如登录场景,用户名输入情况有 n 种,密码的输入情况有 m 种,希望验证用户名和密码,就会涉及到 n*m 种组合的测试用例,如果把这些数据一一的列出来,工作量也是非常大的。pytest 提供了一种参数化的方式,将多组测试数据自动组合,生成大量的测试用例。示例代码如下:

【python】

@pytest.mark.parametrize("x",[1,2])@pytest.mark.parametrize("y",[8,10,11])

def test_foo(x,y):print(f"测试数据组合x: {x} , y:{y}")

运行结果:

【python】
test_mark_paramize.py::test_foo[8-1] 
test_mark_paramize.py::test_foo[8-2] 
test_mark_paramize.py::test_foo[10-1] 
test_mark_paramize.py::test_foo[10-2] 
test_mark_paramize.py::test_foo[11-1] 
test_mark_paramize.py::test_foo[11-2]

分析如上运行结果,测试方法 test_foo( ) 添加了两个 @pytest.mark.parametrize() 装饰器,两个装饰器分别提供两个参数值的列表,2 * 3 = 6 种结合,pytest 便会生成 6 条测试用例。在测试中通常使用这种方法是所有变量、所有取值的完全组合,可以实现全面的测试。

3.2.4 @pytest.fixture 与 @pytest.mark.parametrize 结合

下面讲讲结合 @pytest.fixture 与 @pytest.mark.parametrize 实现参数化。

如果测试数据需要在 fixture 方法中使用,同时也需要在测试用例中使用,可以在使用 parametrize 的时候添加一个参数 indirect=True,pytest 可以实现将参数传入到 fixture 方法中,也可以在当前的测试用例中使用。

parametrize 源码:

【python】
def parametrize(self,argnames, argvalues, indirect=False, ids=None, scope=None):

indirect 参数设置为 True,pytest 会把 argnames 当作函数去执行,将 argvalues 作为参数传入到 argnames 这个函数里。创建“test_param.py”文件,代码如下:

【python】
# 方法名作为参数
test_user_data = ['Tome', 'Jerry']
@pytest.fixture(scope="module")
def login_r(request):
    # 通过request.param获取参数
    user = request.param
    print(f"\n 登录用户:{user}")return user


@pytest.mark.parametrize("login_r", test_user_data,indirect=True)
def test_login(login_r):
    a = login_r
    print(f"测试用例中login的返回值; {a}")
    assert a != "

运行结果:

【plain】
登录用户:Tome PASSED            [50%]测试用例中login的返回值; Tome
登录用户:Jerry PASSED           [100%]测试用例中login的返回值; Jerry

上面的结果可以看出,当 indirect=True 时,会将 login_r 作为参数,test_user_data 被当作参数传入到 login_r 方法中,生成多条测试用例。通过 return 将结果返回,当调用 login_r 可以获取到 login_r 这个方法返回数据。

图1 @pytest.fixture 与 @pytest.mark.parametrize 结合读取数据图例

3.2.5 conftest作用域

其作用范围是当前目录包括子目录里的测试模块。

(1)如果在测试框架的根目录创建conftest.py文件,文件中的Fixture的作用范围是所有测试模块。

(2)如果在某个单独的测试文件夹里创建conftest.py文件,文件中Fixture的作用范围,就仅局限于该测试文件夹里的测试模块。

(3)该测试文件夹外的测试模块,或者该测试文件夹外的测试文件夹,是无法调用到该conftest.py文件中的Fixture。

(4)如果测试框架的根目录和子包中都有conftest.py文件,并且这两个conftest.py文件中都有一个同名的Fixture,实际生效的是测试框架中子包目录下的conftest.py文件中配置的Fixture。

3.3 代码Demo

测试数据存储yaml文件:

【YAML】
测试流程:[
    {"name":"B2B普货运输三方司机流程","senior":{"createTransJobResource":"B2B","createType":"三方","platformType":2}},
    {"name":"B2B普货运输三方司机逆向流程","senior":{"isback":"True","createTransJobResource":"B2B","createType":"三方","platformType":2}},
  ]

测试数据准备,定义统一读取测试数据方法:

【python】
def dataBuilder(key):dires = path.join(dires, "test_data.yaml")
    parameters = laputa_util.read_yaml(dires)[key]
    name = []
    senior = []
    for item in parameters:
        name.append(item['name'] if 'name' in item else '')
        senior.append(item['senior'] if 'senior' in item else '')
    return name, senior

测试用例标识,通过@pytest.mark.parametrize方法驱动用例:

【python】
class TestRegression:
    case, param = dataBuilder('测试流程')


    @pytest.mark.parametrize("param", param, ids=case)
    def test_regression_case(self, param):
        # 调度
        res = create_trans_bill(params)
        trans_job_code = res['data']['jobcode']
        carrier_type = params['createType'] if params['createType'] in ('自营', '三方') else '个体'


        # 执行
        work_info = select_trans_work_info_new(trans_job_code)
        trans_work_code = work_info['trans_work_code']
        if 'isback' in params and params['isback']:
            execute_param.update(isBack=params['isback'])
        execute_bill_core(**execute_param)


        # 结算
        if carrier_type != '自营':
            trans_fee_code = CreateTransFeeBillBase.checkTF(trans_job_code)
    receive_trans_bill_core(**bill_param)

总结

日常测试过程中,无论是通过手动执行或者脚本执行,都需要利用数据驱动设计思路,这有助于提高测试场景覆盖率,测试用例的健壮性和复用性,及需求测试效率。通过数据驱动测试不仅可以得到更好的投资回报率,还可以达到质效合一的测试流程。

 

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

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

相关文章

qq录制视频保存到哪了?qq录制视频怎么没了?找回方法在这

相信很多小伙伴都跟小编一样,使用qq录屏录制好后,结果就怎么也找不到录屏的文件了。经过小编一番研究,终于找到了qq录屏后视频文件的所保存的文件路径了。qq录制视频保存到哪了?别担心,下面小编就带大家一起来找找看。…

VS代码片段(CodeSnippet)的制作以及常用代码片段记录

总目录 文章目录总目录前言一、代码片段是什么?1.了解2.查找代码片段文件夹二、编写代码片段1.认识代码片段2.编写自定义代码片段1、trycf (try,catch,finally)2、propp(用于MVVMLight中)3、ts (创建一个test方法)3.使…

零基础入门:实时音视频技术基础知识全面盘点

1、引言 随着移动网络速度越来越快、质量越来越来,实时音视频技术已经在各种应用场景下全面开花,语音通话、视频通话、视频会议、远程白板、远程监控等等。 实时音视频技术的开发也越来越受到重视,但是由于音视频开发涉及知识面比较广&…

可视化搭建,1天开发1款“智慧楼宇”应用

随着我国城市建设的飞速发展,现代建筑正朝着智能化和网络化不断前进。物联网技术、智能化技术使得建筑内众多公共资源具有语境感知能力,现代建筑进入了智慧楼宇阶段。 天翼物联推出智慧楼宇应用,为物业等管理单位提供安全监控、能源监控、智慧…

【DBN分类】基于哈里斯鹰算法优化深度置信网络HHO-DBN实现数据分类附matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。 🍎个人主页:Matlab科研工作室 🍊个人信条:格物致知。 更多Matlab仿真内容点击👇 智能优化算法 …

oracle学习篇(一)

oracle学习篇(一) 1 oracle属于大型数据库吗? 解答:是的,数据库按照负载量的规模可以分为一下几类 小型数据库:ACCESS 中型数据库:mysql 大型数据库(海量数据):oracle、db22 创建并使用户可用 2.0 前提 必须是要sys或者system这种需要有管理权限的才能进行用户的创建 普通…

链表反转,指定区间反转,k个一组反转---详解

牛客上的三道反转链表的题,入门题,反转链表有很多种做法,本来做第一题的时候是随便写了一种,然后后面发现我用的方法,在做第二题第三题的时候有点繁琐,所以就把三道题一起考虑了一下,选了一种相…

[附源码]Python计算机毕业设计二手图书回收销售网站Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等…

python3.9.0 windows环境搭建

第一步: 下载安装包:CNPM Binaries Mirror 执行exe安装。。。。。 第二步:升级pip 和 setuptools(避免在每一个虚拟环境中都要升级) python -m pip install --upgrade pip python -m pip install --upgrade setuptoo…

基于android音乐播放器的设计

本科毕业论文(设计)诚信声明 本人郑重声明:所呈交的毕业论文(设计),题目《………基于android音乐播放器的设计……………………………》是本人在指导教师的指导下,进行研究工作所取得的成果。对…

ChatGPT写Flask-Demo——有体验地址

ChatGPT中API的试用 最近ChatGPT智能AI很火,可以写代码,DEBUG,写简历等等 上去查看了一下,是可以调用API的,本着学习的态度就是用这个款AI辅助我写了一个demo(本人原来对flask只懂一点点) 目录0…

基于51单片机的数字电压表(ADC0832)(Proteus仿真+程序)

编号:29 基于51单片机的数字电压表(ADC0832) 功能描述: 本设计由51单片机最小系统ADC0832模块两路模拟量输入模块液晶1602显示模块 1、主控制器是AT89C82单片机 2、ADC0832模数转换器进行A/D转换,读取电压两路数据&a…

栅格瓦片和矢量瓦片

地图瓦片 地图瓦片的诞生 在以前没有瓦片的概念时,由于地图要素多、范围大等特点导致地图数据量很大,如果从浏览器可视化地图就对网络和数据渲染能力有高的要求,所以导致瓦片诞生以前,地图多在pc电脑中桌面软件使用。随着互联网…

【YOLOv5】LabVIEW+YOLOv5快速实现实时物体识别(Object Detection)

前言 前面我们给大家介绍了基于LabVIEWYOLOv3/YOLOv4的物体识别(对象检测),今天接着上次的内容再来看看YOLOv5。本次主要是和大家分享使用LabVIEW快速实现yolov5的物体识别,本博客中使用的智能工具包可到主页置顶博客LabVIEW AI视…

一个简单的MATLAB脚本——快速行进算法(FMM))

一个简单的MATLAB脚本——快速行进算法(FMM) 介绍快速行进算法(FMM)的简单MATLAB脚本,不到20行代码实现快速行进算法的运算结果,而且计算速度非常快。给了两个实例模型来说明计算结果。 文章目录一个简单的…

unicloud生成微信小程序分享码

一,方案 看了官方的文档,获取小程序码有三种,我采用的是第二种:生成数量不受限制的分享码。 对应的官方文档:https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/qrcode-link/qr-code/getUnlimitedQRCode.…

MySQL 锁

在之前的文章有多次提到,MySQL在数据更新和性能优化上会用到锁机制。我们在实际的应用中也经常会遇到锁相关的问题,即使很多时候我们并没有人为的为数据库添加锁,但还是会出现死锁的问题,这是因为在我们操作数据时MySQL隐式的帮我…

java UDP通信程序DatagramSocket数据发送

首先 我们先来了解一下 UDP 首先 他是一种不可靠的网络协议 他在通信的两端 各建立一个 Socke对象 但是他们只是 发送和接收数据的对象 发送端只管发送 不会顾及接收端是否接到 接收到只负责接收数据 而不会给出发送端反馈 因此对于UDP通信的双方而言 是有没什么 客户端和服务…

架构师进阶,微服务设计与治理的 16 条常用原则

今天将从存储的上一层「服务维度」学习架构师的第二项常用能力 —— 微服务设计与治理。 如何设计合理的微服务架构? 如何保持微服务健康运行? 这是我们对微服务进行架构设计过程中非常关注的两个问题。 本文对微服务的生命周期定义了七个阶段&#xf…

正大国际期货:为什么外盘期货顺势交易这么难

要回答“为什么趋势交易这么难?”需要先回答:“为什么交易?”。 你应该为了抓住赚取期望利润的机会而交易,为了长期持续赚钱的目的而交易,而不是为了赚得短期利润的喜悦而交易,也不是为了证明你的市场分析…