前言

网盗概念^-^相同的测试脚本使用不同的测试数据来执行,测试数据和测试行为完全分离, 这样的测试脚本设计模式称为数据驱动。(网盗结束)当我们测试某个网站的登录功能时,我们往往会使用不同的用户名和密码来验证登录模块对系统的影响,那么如果我们每一条数据都编写一条测试用例,这无疑是增加了代码量,代码重复,且显得那么臃肿(谁不喜欢身材好的呢?你懂的),这时候我们可以使用不同数据驱动代码执行相同的用例测试不同的场景。

实施数据驱动步骤

我们再来说说实施数据驱动测试的步骤:

1.创建/准备测试数据

2.封装读取数据的方法,保留测试脚本调用的接口/属性(我们需要传递给脚本什么参数)

3.编写自动化测试脚本

4.脚本中调用封装好的处理数据文件的模块并引入测试数据

5.执行测试脚本并分析测试结果

数据驱动测试环境准备

1.安装python3.x开发环境(能看到此文章的应该都有这个环境,没有的自行百度吧)

2.安装数据驱动模块ddt

安装方式1:cmd下执行命令 pip install ddt

安装方式2:https://pypi.org/simple/ddt/ 下载 并解压任意目录,cmd 运行命令python setup.py install

3.验证安装 pycharm 新建python文件并输入 import ddt 运行无报错信息既表示安装成功或者cmd 命令依次输入python回车 import ddt回车 无保存信息表示安装成功

4.unittest框架和ddt进行数据驱动

测试步骤

1.访问地址:https://mail.sohu.com/fe/#/login

2.输入用户名和密码

3.点击登录按钮

4.判断是否登录成功

数据存储

数据存在当前脚本中

数据准备

我们要实现的是用户登录的操作,所以用户名和密码是必须有的,期望结果可以有也可以没有。数据类型看源代码!

实例代码 

 from selenium import webdriver
from ddt import ddt, data, unpack
import unittest
import time
from selenium.common.exceptions import NoSuchWindowException
'''
简单数据驱动测试
'''
@ddt
class ddtTest(unittest.TestCase):
# 数据 可以是元祖, 列表, 字典(可迭代对象)
value = [['13691579846@sohu.com', 'xiaochao11520','https://mail.sohu.com/fe/#/homepage'],
['13691579844@sohu.com', 'xiaochao11520','https://mail.sohu.com/fe/#/homepage']]
# value = [{'uname':'******@sohu.com', 'password':'xiaochao11520','expected':'https://mail.sohu.com/fe/#/homepage'},
# {'uname':'******@sohu.com', 'password':'xiaochao11520','expected':'https://mail.sohu.com/fe/#/homepage'}]
def setUp(self):
self.testUrl = 'https://mail.sohu.com/fe/#/login'
self.driver = webdriver.Firefox()
self.driver.get(self.testUrl) @data(*value) # * 解析数据
@unpack# 用来解包, 将每组数据的第一个数据传递给uname依次类推, 当数据为字典时,形参需和字段的key值相同
def test_case1(self, uname, password, expected):
try:
username = self.driver.find_element_by_xpath("//input[@placeholder='请输入您的邮箱']")
username.send_keys(uname)
time.sleep(1)
userpassword = self.driver.find_element_by_xpath("//input[@placeholder='请输入您的密码']")
userpassword.send_keys(password)
self.driver.find_element_by_xpath("//input[@type='submit']").click()
time.sleep(2)
currenturl = self.driver.current_url
self.assertEqual(expected, currenturl,'登录失败')
except NoSuchWindowException as e:
print(e)
raise
except AssertionError:
print('期望值是{}, 实际值是{}'.format(expected,currenturl))
raise
except Exception:
raise
def tearDown(self):
self.driver.quit()
# pass
if __name__ == '__main__':
unittest.main()

简单数据驱动测试.py

源码分析

1.@ddt来装饰测试类(ddt数据驱动的规范写法,记住就ok)

2.@data(*value)装饰测试用例(也是一种规范,这边又涉及到装饰器,不懂的可以百度或者看我之前的文章又介绍,这边不再赘述,一句话两句话也说不清楚)记住:*value作用是打散数据,比如上面代码是用一个大列表存储两个小列表存放数据的,那么*value会得到两个小列表,每个小列表是一组测试数据

3.@unpack 解析*value数据,会把两个小列表里面的每一个数据取出来分别传递给我们测试用例的形参

方式1缺点

存储大量数据时,需查看源代码,不利于脚本的维护    

json文件读取测试数据进行数据驱动测试

数据准备

新建一个json文件(也可以是txt文件),将我们需要的两组测试数据以列表的形式写到json文件中,每组数据的每一项参数用相同的符号分割开(方便脚本读取数据)

实例代码

{
"value1":"******@sohu.com||xiaochao11520||https://mail.sohu.com/fe/#/homepage",
"value2":"******@sohu.com||xiaochao11520||https://mail.sohu.com/fe/#/homepage"
}

test_data.json

 from selenium import webdriver
from ddt import ddt, file_data
import unittest, time
from selenium.common.exceptions import NoSuchWindowException
import HTMLTestRunner
'''
从文件中读测试数据
''' @ddt # ddt装饰测试类
class Testdata(unittest.TestCase): def setUp(self):
self.driver = webdriver.Firefox()
self.driver.get('https://mail.sohu.com/fe/#/login') @file_data('test_data.json') # 读取文件的 文件中数据可以是一个列表,也可以是一个字典
def test_data(self,value):
uname, password, expected = tuple(value.strip().split('||')) # value是一个字符串
# print(type(value),value)
try:
username = self.driver.find_element_by_xpath("//input[@placeholder='请输入您的邮箱']")
username.send_keys(uname)
time.sleep(1)
userpassword = self.driver.find_element_by_xpath("//input[@placeholder='请输入您的密码']")
userpassword.send_keys(password)
self.driver.find_element_by_xpath("//input[@type='submit']").click()
time.sleep(2)
currenturl = self.driver.current_url
self.assertEqual(expected, currenturl,'登录失败')
except NoSuchWindowException as e:
raise e
except AssertionError:
print('期望值是{}, 实际值是{}'.format(expected,currenturl))
raise
except Exception:
raise def tearDown(self):
self.driver.quit()
if __name__ == '__main__':
unittest.main()
# import os
# from datetime import date
# currentPath = os.path.dirname(os.path.abspath(__file__))# 获取当前文件目录
# reportPath = os.path.join(currentPath,'report') # 创建一个report目录
# if not os.path.exists(reportPath):
# os.mkdir(reportPath) # 判断目录是否存在, 不存在就创建
# reportName = os.path.join(reportPath, str(date.today())+'report.html') # 拼接html报告
# with open(reportName,'wb') as f:
# suite = unittest.TestLoader().loadTestsFromTestCase(Testdata)
# runner = HTMLTestRunner.HTMLTestRunner(stream=f,verbosity=1, title='数据驱动测试报告', description='数据驱动')
# runner.run(suite)

使用数据文件驱动测试.py

源码分析

1.相对上个实例,这里使用了@file_data(文件路径), 参数必须是一个文件,这里是一个json文件, 数据可以是一个列表,也可以是一个字典

# 列表形式
[
"*******@sohu.com||xiaochao11520||https://mail.sohu.com/fe/#/homepage",
"*******@sohu.com||xiaochao11520||https://mail.sohu.com/fe/#/homepage"
]

2.测试用例接收的是一个字符串,需要对字符串进行处理,把用户名,密码,期望值解析出来

方式2优缺点

测试数据存在文件中,方便管理修改,添加数据,易于维护,缺点呢?emmm个人认为这种方式最好!

从xml读取数据进行数据驱动测试

数据准备

新建一个xml格式的文件,按照xml格式的语法需求,填写数据(xml文档我也不是很懂,简单的显示个文字啥的还可以^-^!)

<?xml version="1.0"?>
<bookList type="technolog">
<book>
<uname>******@sohu.com</uname>
<password>xiaochao11520</password>
<expected>https://mail.sohu.com/fe/#/homepage</expected>
</book>
<book>
<uname>******@sohu.com</uname>
<password>xiaochao11520</password>
<expected>https://mail.sohu.com/fe/#/homepage</expected>
</book>
</bookList>

xmlData.xml

实例代码

 from xml.etree import ElementTree

 class ParseXml(object):
def __init__(self, xmlpath):
self.xmlpath = xmlpath # 获取根节点
def getRoot(self):
tree = ElementTree.parse(self.xmlpath)
root = tree.getroot()
return root # 根据根节点查找子节点
def findNodeByName(self, parentNode, nodeName):
nodes = parentNode.findall(nodeName)
return nodes def getNodeOfChildText(self, node):
# 获取节点node下所有子节点的节点名作为key
# 本节点作为value组成的字典对象
childrenTextDict = {}
for i in list(node.iter())[1:]: # node 节点下的所有节点组成的列表
childrenTextDict[i.tag] = i.text
# print(list(node.iter())[1:])
return childrenTextDict # 获取节点node下面的节点的所有数据
def getDataFromXml(self, node):
root = self.getRoot()
books = self.findNodeByName(root, node)
dataList=[]
for book in books:
childrentext = self.getNodeOfChildText(book)
dataList.append(childrentext)
return dataList
if __name__=='__main__':
xml = ParseXml('./xmlData.xml')
root = xml.getRoot()
print(root.tag)
books = xml.findNodeByName(root, 'book') # 查找所有的book节点
for book in books:
# print(book[0].tag, book[0].text)
print(xml.getNodeOfChildText(book))
print(xml.getDataFromXml('book'))

doXML.py

 from dataDdt.doXML import ParseXml
from selenium import webdriver
from selenium.common.exceptions import NoSuchWindowException, TimeoutException
import unittest
from ddt import ddt, data,unpack
import time
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
values = ParseXml('./xmlData.xml')
@ddt
class xmltest(unittest.TestCase): def setUp(self):
self.driver = webdriver.Firefox()
self.driver.get('https://mail.sohu.com/fe/#/login')
@data(*values.getDataFromXml('book'))
@unpack
def test_xml(self,uname, password, expected):
try:
wait = WebDriverWait(self.driver,5)
wait.until(EC.element_to_be_clickable((By.XPATH, "//input[@type='submit']")))
username = self.driver.find_element_by_xpath("//input[@placeholder='请输入您的邮箱']")
username.send_keys(uname)
time.sleep(1)
userpassword = self.driver.find_element_by_xpath("//input[@placeholder='请输入您的密码']")
userpassword.send_keys(password)
self.driver.find_element_by_xpath("//input[@type='submit']").click()
time.sleep(2)
currenturl = self.driver.current_url
self.assertEqual(expected, currenturl, '登录失败')
except TimeoutException as e:
raise e
except NoSuchWindowException as e:
raise e
except AssertionError as e:
print('期望值是{}, 实际值是{}'.format(expected, currenturl))
raise e
except Exception:
raise
def tearDown(self):
self.driver.quit() if __name__=='__main__':
unittest.main()

从xml文件读取数据驱动测试.py

源码分析

1.xml文档编写(深入了解需百度)有点像html,但又有不同,xml中的节点可以是任意名称,每个节点同样是成双出现

2.增加了doXML.py文档,用来解析xml文件,方便脚本获取数据(注释写的很详细,不懂的化可以慢慢调试,哪里不懂print哪里)

3.测试脚本和上面的实例大致相同(不懂的加我qq直接问)

方式3优缺点

优点是做到了数据与测试的分离,方便数据维护,缺点也比较明显,需要对xml文档有一定的了解

总结

上面的数据驱动测试步骤是我自己总结的,看了上面的实例对于步骤应该还算合理,下面是我在网上找到的数据驱动测试步骤(感觉比较官方!大家可以参考)

1.编写测试脚本, 脚本需要支持从程序对象, 文件,或者数据库读入数据。(个人观点:如果脚本先编写完,测试数据还未准备,后期还要做修改)

2.将测试脚本使用的测试数据存入程序对象,文件,或者数据库等外部介质中。(个人观点:这个阶段实为准备数据的阶段,也就是我们数据要存在哪里,理应放在第一步)

3.运行脚本过程中,循环调用存储在外部介质中的测试数据。(个人观点:这里要考虑我们如何读取,使用数据)

4.验证所有的测试结果是否符合预期结果

ps:源码已经上传到我的git,地址:https://github.com/13691579846/WebdriverAPI 欢迎交流讨论QQ交流群:878565760

如何快速掌握DDT数据驱动测试?的更多相关文章

  1. 【python接口自动化】- DDT数据驱动测试

    简单介绍 ​ DDT(Date Driver Test),所谓数据驱动测试,简单来说就是由数据的改变从而驱动自动化测试的执行,最终引起测试结果的改变.通过使用数据驱动测试的方法,可以在需要验证多组数据 ...

  2. 【python】以souhu邮箱为例学习DDT数据驱动测试

    前言 DDT(Data-Driven Tests)是针对 unittest 单元测试框架设计的扩展库.允许使用不同的测试数据来运行一个测试用例,并将其展示为多个测试用例.通俗理解为相同的测试脚本使用不 ...

  3. python Unittest+excel+ddt数据驱动测试

    #!user/bin/env python # coding=utf- # @Author : Dang # @Time : // : # @Email : @qq.com # @File : # @ ...

  4. Python3|ddt|unittest|浅议数据驱动测试

    目录 1.DDT简介 2.data装饰器 3.unpack装饰器 4.file_data装饰器 5.总结 1.DDT简介 Data-Driven Tests(DDT)即数据驱动测试.它允许您通过不同的 ...

  5. python - 数据驱动测试 - ddt

    # -*- coding:utf-8 -*- ''' @project: jiaxy @author: Jimmy @file: study_ddt.py @ide: PyCharm Communit ...

  6. Python3-unittest测试框架之DDT数据驱动

    unittest测试框架之DDT数据驱动 ddt的使用 DDT数据驱动 DDT:Data Driver Test(数据驱动测试) 数据驱动思想:数据和用例进行分离,通过外部数据去生成测试用例 安装 p ...

  7. [ddt01篇]十年测试老鸟帮您解析:ddt数据驱动实现自动化测试入门基础应用

    一.什么是DDT数据驱动框架 ​ 全称:data driver test数据驱动测试框架,可以完美的应用于unittest框架实现数据驱动.ddt使用简介: 1.测试数据为多个字典的list类型 2. ...

  8. 基于Python的接口自动化-unittest测试框架和ddt数据驱动

    引言 在编写接口自动化用例时,我们一般针对一个接口建立一个.py文件,一条接口测试用例封装为一个函数(方法),但是在批量执行的过程中,如果其中一条出错,后面的用例就无法执行,还有在运行大量的接口测试用 ...

  9. 基于python的接口自动化测试+ddt数据驱动

    在测试接口时,一个接口会先写好测试用例,这个用例主要针对功能,传入参时考虑到各种场景,正常的,异常的,如:参数缺省,参数传一个六位数字写用例时考虑边界情况等. 一个接口设计用例时有可能会十几条到几十条 ...

随机推荐

  1. PowerDesigner如何将设计的表更新到数据库中

    前言: 软件开发的过程中,将设计的表更新到数据库中是一件繁琐的事情,使用好工具,能够事半功倍. 环境介绍:Oracle 11g x64 前期准备: 1.PowerDesigner工具(本人是32位的) ...

  2. 分布式计算框架Gearman原理详解

    什么是Gearman? Gearman提供了一个通用的应用程序框架,用于将工作转移到更适合于工作的其他机器或流程.它允许你并行工作,负载平衡处理,并在语言间调用函数.它可用于从高可用性网站到传输数据库 ...

  3. js文件引用的问题顺带复习css引用

    js文件包含在<script>块中用scr引用,css在link和@import来引用,css不是本篇的重点,直接引用一个博主的总结: “ 区别1:link是XHTML标签,除了加载CSS ...

  4. javascript系列2 -- 闭包详解

    转发请标明来源:http://www.cnblogs.com/johnhou/p/javascript.html  请尊重笔者的劳动成果  --John Hou 今天我们从内存结构上来讲解下 java ...

  5. 科学计算工具Numpy

    参考学习资料: Python.NumPy和SciPy介绍:http://cs231n.github.io/python-numpy-tutorial NumPy和SciPy快速入门:https://d ...

  6. MVC之图片验证码

    MVC之图片验证码 controller中的action方法public ActionResult GetValidateCode() { ValidateCode vCode = new Valid ...

  7. Elasticsearch笔记八之脑裂

    Elasticsearch笔记八之脑裂 概述: 一个正常es集群中只有一个主节点,主节点负责管理整个集群,集群的所有节点都会选择同一个节点作为主节点所以无论访问那个节点都可以查看集群的状态信息. 而脑 ...

  8. BZOJ_1774_[Usaco2009 Dec]Toll 过路费_floyd

    BZOJ_1774_[Usaco2009 Dec]Toll 过路费_floyd 题意: 跟所有人一样,农夫约翰以着宁教我负天下牛,休叫天下牛负我的伟大精神,日日夜夜苦思生 财之道.为了发财,他设置了一 ...

  9. .NET 创建 classlib时,netcoreapp2.0与netstandard2.0的区别

    最近单位在开发一个新项目,在技术选型的时候,我们决定后台代码全部使用 dot net core来进行开发. 当项目引用公司之前的一个类库的时候,总是出现缺少XX组件的错误,所以我们检查了所有的类库,将 ...

  10. ModBus功能码速记

    一.0x01~0x04: 这四个功能码都是"读"操作,可分两组记忆,0x01和0x02是一组(bool类型),0x03和0x04是一组(寄存器类型):两组属性差不多如下: 1.都是 ...