前言

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

实施数据驱动步骤

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

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. elasticSearch+spring 整合 maven依赖详解

    摘自:http://www.mayou18.com/detail/nTxPQSyu.html [Elasticsearch基础]elasticSearch+spring 整合 maven依赖详解 Ma ...

  2. echart css样式弄了几个月了,样式一直都没有好好解决,好激动

    legend 图例,每个图表最多仅有一个图例.try this » 名称 默认值 描述 {string} orient 'horizontal' 布局方式,默认为水平布局,可选为:'horizonta ...

  3. Fedora Linux中解决“xxx不在sudoers文件中”

    问题描述: 在Fedora中执行一些操作时需要使用root权限,当我使用命令: sudo 想在普通用户中临时获得root权限时,却被提示: "xxx 不在 sudoers 文件中.此事将被报 ...

  4. Spring boot +Spring Security + Thymeleaf 认证失败返回错误信息

    [Please make sure to select the branch corresponding to the version of Thymeleaf you are using] Stat ...

  5. elementui左侧菜单栏刷新后还是原来的状态

    <template> <div id="leftMenuList"> <el-row> <el-col :span="24&qu ...

  6. Mongodb数据库操作

     mysql/mongodb对比 CREATE TABLE USERS (a Number, b Number) Implicit or use MongoDB::createCollection() ...

  7. bmob云代码中生成缩略图

    function onRequest(request, response, modules) { var options = { url:"https://api.bmob.cn/1/ima ...

  8. 错误:编码GBK的不可映射字符

    当Java源代码中包含中文字符时,我们在用javac编译时会出现"错误:编码GBK的不可映射字符". 由于JDK是国际版的,我们在用javac编译时,编译程序首先会获得我们操作系统 ...

  9. Java中存取权限和修饰符public、private、protected和default的区别和联系

    java中有4种存取权限和对应的修饰符(从限制最少的开始列出),主要作用如下: 1.public权限最大,代表任何程序代码都可以存取的公开事物(类.变量.方法.构造函数等).它往往用于对外的情况,也就 ...

  10. Clean http handlers in Go

    Introduction For this blog post we are going to take a look at the http.HandlerFunc type and how we ...