在前面的设计中,已经实现了配置信息的分离,并且添加了log日志,接下来我们应该尝试着进行数据分离,进行参数化了。修改file_reader1.py文件,添加ExcelReader类读取xlrd,实现读取excel内容的功能:
首先在工程framework下创建一个data的package,并在PC本地的data目录下创建一个baidu.excel包含数据的表格。
加入了去excel功能的file_reader1.py的模块如下:
#coding:utf-8
"""
file_reader1.py:文件读取。YamlReader读取yaml文件,ExcelReader读取excel。
"""
import yaml
import os
from xlrd import open_workbook
class YamReader():
def __init__(self,yaml):
if os.path.exists(yaml):
self.yaml = yaml
else:
raise IOError("文件不存在!")
self._data = None
@property
def data(self):
#如果是第一次调用data,读取yaml文档,否则直接返回之前保存的数据
if not self._data:
with open(self.yaml,'rb') as f:
#load之后是一个generator,用list组织成列表
self._data = list(yaml.safe_load_all(f))
return self._data
class SheetTypeError(Exception):
pass
class ExcelReader():
"""
读取excel文件中的内容。返回list。
"""
def __init__(self,excel,sheet = 0,title_line = True):
if os.path.exists(excel):
self.excel = excel
else:
raise IOError("The excel file does not exist!")
self.sheet = sheet
self.title_line = title_line
self._data = list()
@property
def data(self):
if not self._data:
workbook = open_workbook(self.excel)
if type(self.sheet) not in [int ,str]:
raise SheetTypeError("Please pass in <type int> or <type str>,not {0}".format(type(self.sheet)))
elif type(self.sheet) == int:
s = workbook.sheet_by_index(self.sheet)
else:
s = workbook.sheet_by_name(self.sheet)
if self.title_line:
#the first row is title
title = s.row_values(0)
for col in range(1,s.nrows):
#依次遍历其余的行,与首行组成dict,拼接到seld._data中
self._data.append(dict(zip(title,s.row_values(col))))
else:
for col in range(0,s.nrows):
#遍历所有行,拼到s._data中
self._data.append(s.row_values(col))
return self._data
if __name__ == "__main__":
here = os.path.dirname(os.path.dirname(__file__))
config_path = os.path.join(here, 'config/config.yaml')
#y = r"F:\py_test\Framework\config\config.yaml"
reader = YamReader(config_path)
print (reader.data)
#e = r"F:/py_test/Framework/data/baidu.xlsx"
excel_path = os.path.join(here,'data/baidu.xlsx')
print excel_path
reader = ExcelReader(excel_path)
print (reader.data)
对于属性定义采用类似C++中的私有方法,使用_data的形式,可参考_*、__*、__*__的区别,可以指定sheet,通过index或者name进行数据访问,为了测试本模块的功能,excel中的数据如下:
ExcelReader(excel,sheet =2) 或者 ExcelReader(excel,sheet = 'BaiduTest');此外设计了title_line标识位来判断excel中是否标题行,如果有标题行,返回dict列表,如果无标题行,则返回list列表.
有标题行:print(ExcelReader(excel_path,title_line = True).data),则输出为:
无标题行:print(ExcelReader(excel_path,title_line = False).data),则输出为:
这里在excel中存储的搜索数据为:
对于test_baidu4.py模块,进行相应的修改:
#coding:utf-8
"""test_baidu4.py 加入读取excel表中数据的功能"""
import os
import time
import unittest
from selenium import webdriver
from selenium.webdriver.common.by import By
from Framework.utils.config import Config, DRIVER_PATH, DATA_PATH
from Framework.utils.log import logger
from Framework.utils.file_reader1 import ExcelReader
class TestBaiDu(unittest.TestCase):
driver = None
URL = Config().get('URL')
#excel = DATA_PATH + '/baidu.xlsx'
excel = os.path.join(DATA_PATH,'baidu.xlsx')
locator_kw = (By.ID, 'kw')
locator_su = (By.ID, 'su')
locator_result = (By.XPATH, '//div[contains(@class, "result")]/h3/a')
def sub_setUp(self):
self.driver = webdriver.Chrome(executable_path=DRIVER_PATH + '\chromedriver.exe')
self.driver.get(self.URL)
def sub_tearDown(self):
self.driver.quit()
################################################################################################
def test_search(self):
datas = ExcelReader(self.excel).data
print datas
for d in datas:
self.sub_setUp()
print self.driver
self.driver.find_element(*self.locator_kw).send_keys(d['search'])
self.driver.find_element(*self.locator_su).click()
time.sleep(1)
#links = self.driver.find_element(*self.locator_result) #错误信息定位,TypeError:'WebElement object is not iterable
links = self.driver.find_elements(*self.locator_result) #错误信息更正
for link in links:
logger.info(link.text)
self.sub_tearDown()
##############################################################################################
if __name__ == '__main__':
unittest.main(verbosity=2)
Python 3的使用越来越多,而且3的unittest中带有subTest,能够通过子用例实现参数化。而用2的话需要unittest2或其他的库来实现。如果是py3,将上面###之间的代码替换如下就可以了,可以直接调用subTest()方法
def test_search(self):
datas = ExcelReader(self.excel).data
for d in datas:
with self.subTest(data=d):
self.sub_setUp()
self.driver.find_element(*self.locator_kw).send_keys(d['search'])
self.driver.find_element(*self.locator_su).click()
time.sleep(2)
links = self.driver.find_elements(*self.locator_result)
for link in links:
logger.info(link.text)
self.sub_tearDown()
运行的时候,可以正常搜索selenium,但是没有运行python selenium的搜索,提示:TypeError:'WebElement' object is not iterable:
通过在日志打印的for循环加上打印进行定位,发现因为要搜索的是一组元素就是“selenium”和“python selenium”但是使用的元素定位方法是find_element,这里应该使用的是find_elements(),在上述test_baidu4.py中已经指出并进行了更正,即为:
#修改错误:TypeError:'WebElement' object is not iterable
#links = self.driver.find_element(*self.locator_result) #错误信息定位,TypeError:'WebElement object is not iterable
links = self.driver.find_elements(*self.locator_result) #错误信息更正
为了便于理解其中的执行流程,在test_baidu4.py中加了打印信息,输出结果:
这样就实现了数据的分离,后面要搜索什么,只需要添加在excel中就可以了。