DDT数据驱动
什么是数据驱动?
在测试活动中经常会使用相同的测试脚本使用不同的测试数据来执行,测试数据和测试行为完全分离, 这样的测试脚本设计模式称为数据驱动。例如:当我们测试某个网站的登录功能时,往往我们会使用不同的用户名和密码来验证登录模块对系统的影响,那么如果我们每一条数据都编写一条测试用例,这无疑是增加了代码量,代码重复冗余很多,这时候我们可以使用不同数据执行相同的用例测试不同的场景。
实施数据驱动步骤
我们再来说说实施数据驱动测试的步骤:
1.创建测试数据
2.封装读取数据的方法,保留测试脚本调用的接口/属性(我们需要传递给脚本什么参数)
3.编写自动化测试脚本
4.脚本中调用封装好的处理数据文件的模块并引入测试数据
5.执行测试脚本并分析测试结果
数据驱动测试环境准备
1.安装python3.x开发环境(能看到此文章的应该都有这个环境,没有的自行百度吧)
2.安装数据驱动模块ddt
#安装方式:cmd下执行命令:
pip install ddt
3.验证安装 pycharm 新建python文件并导入 import ddt 运行无报错信息既表示安装成功或者cmd 命令依次输入python回车 import ddt回车 无保存信息表示安装成功
4.unittest框架和ddt进行数据驱动
测试步骤
1.访问地址:http://192.168.23.144:8888/WoniuBoss4.0/login/logout
2.输入用户名和密码
3.点击登录按钮
4.判断是否登录成功
数据存储
数据存在当前脚本中
数据准备
我们要实现的是用户登录的操作,所以用户名和密码是必须有的,期望结果可以有也可以没有。
实例代码
import unittest
import ddt
from openpyxl import load_workbook
from selenium import webdriver
def Excelread():
"""usernamelist返回的格式为:[['WNCD000', 'woniu123'], ['WNCD001', 'woniu456']]"""
wb = load_workbook('woniuboss.xlsx')
sheet = wb['登录']
rows = sheet.max_row
usernamelist = []
#取出表格中有用的数据信息
for one in range(2, rows+1):
#取出姓名
name = sheet.cell(one, 2).value
password = sheet.cell(one, 3).value
usernamelist.append([name, password])
wb.close()
return usernamelist
@ddt.ddt
class Logincases(unittest.TestCase):
a = 5
b = 2
@classmethod
def setUpClass(cls) -> None:
print("in class setUpClass")
@classmethod
def tearDownClass(cls) -> None:
print("in class tearDown")
def setUp(self) -> None:
print("in setUp")
def tearDown(self) -> None:
print("in tearDown")
# 数据 可以是元祖, 列表, 字典(可迭代对象)
#value
value = Excelread()
#装饰器@ddt.data是用来将value拆开成['WNCD000', 'woniu123']
@ddt.data(*value)
#unpack则是将['WNCD000', 'woniu123']两个元素分别赋值传入给uname和passwd
@ddt.unpack
def test_login(self, uname, passwd):
self.driver = webdriver.Chrome()
self.driver.get('http://192.168.23.144:8888/WoniuBoss4.0/login/logout')
self.driver.implicitly_wait(15)
self.driver.find_element_by_name('userName').send_keys(uname)
self.driver.find_element_by_name('userPass').send_keys(passwd)
self.driver.find_element_by_name('checkcode').click()
self.driver.find_element_by_name('checkcode').send_keys("0000")
self.driver.find_element_by_css_selector('button[onclick="login();"]').click()
if __name__ == '__main__':
Logincases.main()
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 @ddt 10 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_url 33 self.assertEqual(expected, currenturl,'登录失败') 34 except NoSuchWindowException as e: 35 print(e) 36 raise 37 except AssertionError: 38 print('期望值是{}, 实际值是{}'.format(expected,currenturl)) 39 raise 40 except Exception: 41 raise 42 def tearDown(self): 43 self.driver.quit() 44 # pass 45 if __name__ == '__main__': 46 unittest.main()
源码分析
1.@ddt来装饰测试类
2.@data(*value)装饰测试用例,注意:*value作用是打散数据,比如上面代码是用一个大列表存储两个小列表存放数据的,那么*value会得到两个小列表,每个小列表是一组测试数据
3.@unpack 解析*value数据,会把两个小列表里面的每一个数据取出来分别传递给我们测试用例的形参