上一篇实现了将读取页面内元素所需的type和type名存入ini文件中,并读取,然后操作页面成功。
但是登录时填入的用户名和用户密码还是手动输入的。这样不好。
我们写一个excel文件,用户名,密码等都从中读取。
一.数据驱动
比如在测试登录时,除了正确的用户名和密码,我们还可能输入错误的密码,密码为空等多种情况。
和正确的一组用户名密码相比,仅仅是输入的数据不一样,我们不可能因为有n种的输入组合就将代码重复n遍。
这就是数据驱动的作用,将数据与代码分离。登录行为的代码独立,需要用到不同组合的用户民密码到文件中取。
在项目中新建一个package:TestData
然后再准备一个excel文件,内容如下:
将这个excel文件复制到TestData包下
然后我们到ConfigPath.py里获取xlsx文件的路径。
xlsxPath = os.path.join(ParentDirPath,u'TestData\LoginData.xlsx')
获取到excel文件的位置之后,接下来就是对其中数据进行处理了。
在命令行安装openpyxl模块
在Utils包下新建ExcelOperate.py文件,并导入openpyxl
在其中写入以下两个函数,使用load_work等库的内置方法,根据名字分别读取xlsx文件以及文件内的页。
再写入以下几个函数来获取sheet的最大行列,以及获取某一行所有的值:
以上几个方法大部分都是openpyxl中自带的,我们稍微封装一下,接下来写个main函数测试这个页面的代码是否有误。
成功,与excel里的数据都对的上。
贴一下代码:
import openpyxl
from openpyxl import load_workbook
from ConfigFiles.ConfigPath import xlsxPath
class ExcelOperate:
def __init__(self):
self.workbook = None
self.sheet = None
def load_workbook(self,filename):
'''
加载相应的excel文件
:param filename:
:return:
'''
try:
self.workbook = load_workbook(filename)
except Exception as e:
print(e)
def get_sheet_by_name(self,sheetname):
'''
拿到xlsx文件里对应的页
:param sheetname:
:return:
'''
try:
self.sheet = self.workbook[sheetname]
except Exception as e:
print(e)
def get_rows_nums(self):
'''
返回当前页的最大行数
:return:
'''
return self.sheet.max_row
def get_col_nums(self):
'''
获取最大列数
:return:
'''
return self.sheet.max_column
def get_row_values(self,row):
'''
根据row获取某一行的值
:param row:
:return:
'''
columns = self.sheet.max_column
row_data = []
#遍历列的时候从1开始,不是从0开始,因为xlsx没有第0行,第0列
for i in range(1,columns+1):
cell_value = self.sheet.cell(row = row,column = i).value
row_data.append(cell_value)
return row_data
def get_cell_value(self,row,column):
'''
获取某一个单元格的值
:param row:
:param column:
:return:
'''
cell_value = self.sheet.cell(row= row,column=column).value
return cell_value
if __name__ == '__main__':
eo = ExcelOperate()
#根据名字读取xlsx文件,xlsxPath已经在ConfigPath.py文件中定义过了
eo.load_workbook(xlsxPath)
eo.get_sheet_by_name('Sheet1')
print(eo.get_col_nums())
print(eo.get_rows_nums())
print(eo.get_row_values(1))
print(eo.get_cell_value(1,1))
二.改造业务层代码
打开LoginCases.py文件,将之前的登录操作语句注释掉
然后改为如下这段代码,成功获取xlsx文件里的内容并封装为字典。
然后我们根据excel文件里的is_executed字段来判断这行数据是否要执行。
运行一下.
结果是第一组数据运行成功,登录进入邮箱。
在运行第二组数据的时候报错了
原因是我们将driver定义在函数外了,而在运行完第一组数据结束,也就是第一个for循环结束时加了一行代码:driver.quit(),释放了driver,导致在第二个for循环运行第二行数据的时候,没有driver可以用了,于是报错。
个人亲测将driver定义在for循环下,每次循环就申明一次driver就不会报错,可以正常运行了。
我个人认为大多数情况下中,跑多行数据,大概率是在跑完一次就清空输入框,再接着输入下一行数据,不会这样反复申明释放driver。
贴一下代码:
import time
from selenium import webdriver
from ConfigFiles.ConfigPath import xlsxPath
from Modules.LoginAction import LoginAction
from Utils.ExcelOperate import ExcelOperate
def test_login():
login_action = LoginAction()
excelOperate = ExcelOperate()
excelOperate.load_workbook(xlsxPath)
excelOperate.get_sheet_by_name('Sheet1')
#获取最大行数
row_nums = excelOperate.get_rows_nums()
#获取第一行的值
row_1_values = excelOperate.get_row_values(1)
for i in range(2,row_nums+1):
row_values = excelOperate.get_row_values(i)
#第一行与其他行组装成一个字典
#zip函数将可迭代的两个对象中的对应的元素一一映射并打包成元组,并将所有这些元组放入一个列表中
values = dict(zip(row_1_values,row_values))
# is_executed的值为y则代表这行数据要执行
if values['is_executed'] == 'y':
username = values['username']
password = values['password']
#申明driver
driver = webdriver.Chrome()
driver.get('https://mail.163.com/')
driver.maximize_window()
login_action.do_login(driver, username, password)
time.sleep(2)
driver.quit()
if __name__ == '__main__':
test_login()
这样数据驱动就成功啦。