来自 技术 2019-03-16 00:00 的文章

如何快速掌握DDT数据驱动测试? - linux超

1.前言

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

2.实施数据驱动步骤

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

  1.创建/准备测试数据

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

  3.编写自动化测试脚本

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

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

3.数据驱动测试环境准备

  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进行数据驱动

4.测试步骤

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

  2.输入用户名和密码

  3.点击登录按钮

  4.判断是否登录成功

5.数据驱动测试方式  方式1:数据存在当前脚本中  1.1数据准备

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

  1.2实例代码 

1 from selenium import webdriver 2 from ddt import ddt, data, unpack 3 import unittest 4 import time 5 from selenium.common.exceptions import NoSuchWindowException 6 ''' 7 简单数据驱动测试 8 ''' 9 @ddt10 class ddtTest(unittest.TestCase):11 # 数据 可以是元祖, 列表, 字典(可迭代对象)12 value = [['13691579846@sohu.com', 'xiaochao11520','https://mail.sohu.com/fe/#/homepage'],13 ['13691579844@sohu.com', 'xiaochao11520','https://mail.sohu.com/fe/#/homepage']]14 # value = [{'uname':'******@sohu.com', 'password':'xiaochao11520','expected':'https://mail.sohu.com/fe/#/homepage'},15 # {'uname':'******@sohu.com', 'password':'xiaochao11520','expected':'https://mail.sohu.com/fe/#/homepage'}]16 def setUp(self):17 self.testUrl = 'https://mail.sohu.com/fe/#/login'18 self.driver = webdriver.Firefox()19 self.driver.get(self.testUrl)20 21 @data(*value) # * 解析数据22 @unpack# 用来解包, 将每组数据的第一个数据传递给uname依次类推, 当数据为字典时,形参需和字段的key值相同23 def test_case1(self, uname, password, expected):24 try:25 username = self.driver.find_element_by_xpath("//input[@placeholder='请输入您的邮箱']")26 username.send_keys(uname)27 time.sleep(1)28 userpassword = self.driver.find_element_by_xpath("//input[@placeholder='请输入您的密码']")29 userpassword.send_keys(password)30 self.driver.find_element_by_xpath("//input[@type='submit']").click()31 time.sleep(2)32 currenturl = self.driver.current_url33 self.assertEqual(expected, currenturl,'登录失败')34 except NoSuchWindowException as e:35 print(e)36 raise37 except AssertionError:38 print('期望值是{}, 实际值是{}'.format(expected,currenturl))39 raise40 except Exception:41 raise42 def tearDown(self):43 self.driver.quit()44 # pass45 if __name__ == '__main__':46 unittest.main()简单数据驱动测试.py  1.3源码分析

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

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

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

   1.4方式1缺点

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

  方式2:json文件读取测试数据进行数据驱动测试   2.1数据准备

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

  2.2实例代码

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

1 from selenium import webdriver 2 from ddt import ddt, file_data 3 import unittest, time 4 from selenium.common.exceptions import NoSuchWindowException 5 import HTMLTestRunner 6 ''' 7 从文件中读测试数据 8 ''' 9 10 @ddt # ddt装饰测试类11 class Testdata(unittest.TestCase):12 13 def setUp(self):14 self.driver = webdriver.Firefox()15 self.driver.get('https://mail.sohu.com/fe/#/login')16 17 @file_data('test_data.json') # 读取文件的 文件中数据可以是一个列表,也可以是一个字典18 def test_data(self,value):19 uname, password, expected = tuple(value.strip().split('||')) # value是一个字符串20 # print(type(value),value)21 try:22 username = self.driver.find_element_by_xpath("//input[@placeholder='请输入您的邮箱']")23 username.send_keys(uname)24 time.sleep(1)25 userpassword = self.driver.find_element_by_xpath("//input[@placeholder='请输入您的密码']")26 userpassword.send_keys(password)27 self.driver.find_element_by_xpath("//input[@type='submit']").click()28 time.sleep(2)29 currenturl = self.driver.current_url30 self.assertEqual(expected, currenturl,'登录失败')31 except NoSuchWindowException as e:32 raise e33 except AssertionError:34 print('期望值是{}, 实际值是{}'.format(expected,currenturl))35 raise36 except Exception:37 raise38 39 def tearDown(self):40 self.driver.quit()41 if __name__ == '__main__':42 unittest.main()43 # import os44 # from datetime import date45 # currentPath = os.path.dirname(os.path.abspath(__file__))# 获取当前文件目录46 # reportPath = os.path.join(currentPath,'report') # 创建一个report目录47 # if not os.path.exists(reportPath):48 # os.mkdir(reportPath) # 判断目录是否存在, 不存在就创建49 # reportName = os.path.join(reportPath, str(date.today())+'report.html') # 拼接html报告50 # with open(reportName,'wb') as f:51 # suite = unittest.TestLoader().loadTestsFromTestCase(Testdata)52 # runner = HTMLTestRunner.HTMLTestRunner(stream=f,verbosity=1, title='数据驱动测试报告', description='数据驱动')53 # runner.run(suite)使用数据文件驱动测试.py  2.3源码分析

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

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

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

  2.4方式2优缺点

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

  方式3:从xml读取数据进行数据驱动测试  3.1数据准备

    新建一个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  3.2实例代码

1 from xml.etree import ElementTree 2 3 class ParseXml(object): 4 def __init__(self, xmlpath): 5 self.xmlpath = xmlpath 6 7 # 获取根节点 8 def getRoot(self): 9 tree = ElementTree.parse(self.xmlpath)10 root = tree.getroot()11 return root12 13 # 根据根节点查找子节点14 def findNodeByName(self, parentNode, nodeName):15 nodes = parentNode.findall(nodeName)16 return nodes17 18 def getNodeOfChildText(self, node):19 # 获取节点node下所有子节点的节点名作为key20 # 本节点作为value组成的字典对象21 childrenTextDict = {}22 for i in list(node.iter())[1:]: # node 节点下的所有节点组成的列表23 childrenTextDict[i.tag] = i.text24 # print(list(node.iter())[1:])25 return childrenTextDict26 27 # 获取节点node下面的节点的所有数据28 def getDataFromXml(self, node):29 root = self.getRoot()30 books = self.findNodeByName(root, node)31 dataList=[]32 for book in books:33 childrentext = self.getNodeOfChildText(book)34 dataList.append(childrentext)35 return dataList36 if __name__=='__main__':37 xml = ParseXml('./xmlData.xml')38 root = xml.getRoot()39 print(root.tag)40 books = xml.findNodeByName(root, 'book') # 查找所有的book节点41 for book in books:42 # print(book[0].tag, book[0].text)43 print(xml.getNodeOfChildText(book))44 print(xml.getDataFromXml('book'))doXML.py

1 from dataDdt.doXML import ParseXml 2 from selenium import webdriver 3 from selenium.common.exceptions import NoSuchWindowException, TimeoutException 4 import unittest 5 from ddt import ddt, data,unpack 6 import time 7 from selenium.webdriver.support import expected_conditions as EC 8 from selenium.webdriver.support.ui import WebDriverWait 9 from selenium.webdriver.common.by import By10 values = ParseXml('./xmlData.xml')11 @ddt12 class xmltest(unittest.TestCase):13 14 def setUp(self):15 self.driver = webdriver.Firefox()16 self.driver.get('https://mail.sohu.com/fe/#/login')17 @data(*values.getDataFromXml('book'))18 @unpack19 def test_xml(self,uname, password, expected):20 try:21 wait = WebDriverWait(self.driver,5)22 wait.until(EC.element_to_be_clickable((By.XPATH, "//input[@type='submit']")))23 username = self.driver.find_element_by_xpath("//input[@placeholder='请输入您的邮箱']")24 username.send_keys(uname)25 time.sleep(1)26 userpassword = self.driver.find_element_by_xpath("//input[@placeholder='请输入您的密码']")27 userpassword.send_keys(password)28 self.driver.find_element_by_xpath("//input[@type='submit']").click()29 time.sleep(2)30 currenturl = self.driver.current_url31 self.assertEqual(expected, currenturl, '登录失败')32 except TimeoutException as e:33 raise e34 except NoSuchWindowException as e:35 raise e36 except AssertionError as e:37 print('期望值是{}, 实际值是{}'.format(expected, currenturl))38 raise e39 except Exception:40 raise41 def tearDown(self):42 self.driver.quit()43 44 if __name__=='__main__':45 unittest.main()从xml文件读取数据驱动测试.py  3.3源码分析

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

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

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

  3.4方式3优缺点

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

6.总结

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

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

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

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

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

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