Python+Selenium+PageObject模式 (一)
把页面设计成一个类,页面中的控件作为属性,控件操作作为方法
一个类代表一个页面 属性代表元素 方法代表元素的操作
业务分层:
V1.0.0:一个类实现登录禅道:element_infos文件夹-login_page.py
import os
from selenium import webdriver
from selenium.webdriver.common.by import By
class LoginPage:
def __init__(self):
self.driver = webdriver.Chrome()
self.driver.implicitly_wait(10)
self.driver.maximize_window()
self.driver.get('浏览器地址')#打开浏览器
self.username_inputbox = self.driver.find_element(By.ID,'account')#定位用户名元素
self.password_inputbox= self.driver.find_element(By.NAME,'password')#定位密码元素
self.login_button = self.driver.find_element(By.CLASS_NAME,'btn.btn-primary')#定位提交按钮元素
self.keeplogin_checkbox = None
def input_username(self,username):#定义用户名控件的操作
self.username_inputbox.send_keys(username)
def input_password(self,password):#定义密码控件的操作
self.password_inputbox.send_keys(password)
def click_login(self):#定义登录按钮的操作
self.login_button.click()
if __name__ == '__main__':
login_page = LoginPage()#创建login_page对象
login_page.input_username('用户名')#调用LoginPage类中的用户控件操作方法
login_page.input_password('密码')#调用LoginPage类中的密码控件操作方法
login_page.click_login()#调用LoginPage类中的登录操作方法
V1.0.1:基于V1.0.0,element_infos文件夹创建mian_page.py,引用login_page.py中的登录方法,识别其他元素
import os
from selenium import webdriver
from selenium.webdriver.common.by import By
from element_infos.login_page import LoginPage
class Main_Page:
def __init__(self):
#此处是调用login_page.py中的方法完成登录的操作
login_page = LoginPage()
login_page.input_username('用户名')
login_page.input_password('密码')
login_page.click_login()
self.driver = login_page.driver#将login_page对象传给Main_page获取login_page的driver属性
self.companyname_showbox = self.driver.find_element(By.XPATH,'//h1[@id="companyname"]')#定位公司名称元素
self.myzone_menu = self.driver.find_element(By.XPATH,'//li[@data-id="my"]')#定位我的地盘元素
self.product_menu = self.driver.find_element(By.XPATH,'//li[@data-id="product"]')#定位产品菜单元素
self.username_showspan = self.driver.find_element(By.XPATH,'//span[@class="user-name"]')
def get_companyname(self):#定义获取公司名称的方法
value = self.companyname_showbox.get_attribute('title')#获取公司名
return value
def goto_myzone(self):#定义进入我的地盘菜单操作的方法
self.myzone_menu.click()
def goto_product(self):#定义产品菜单操作的方法
self.product_menu.click()
def get_username(self):#定义获取用户名的方法
value = self.username_showspan.text#获取用户名
return value
if __name__ == '__main__':
main_page = Main_Page()#创建mian_page对象
username = main_page.get_username()#通过调用main_page中的获取用户名方法获取用户名
print(username)
V1.0.2:common文件夹创建base_page.py(封装公共操作),日志模块log_utils.py
import os
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from common.log_utils import logger
#由先识别完所有元素改为分步识别
class BasePage(object): #封装浏览器的基础操作及元素识别方法
def __init__(self,driver):
self.driver = driver
# self.driver = webdriver.Chrome() #先写此语法后续封装时可自动调用语法,若直接写第一步,则所有基础语法代码均要一个个敲
#浏览器操作封装->二次封装实现更多功能
def open_url(self,url):
self.driver.get(url)
logger.info('打开URL地址%s'%url)
def set_browser_max(self):
self.driver.maximize_window()
logger.info('设置浏览器最大化')
def set_browser_min(self):
self.driver.minimize_window()
logger.info('设置浏览器最小化')
def quit_browser(self):
self.driver.quit()
logger.info('成功退出浏览器')
def refresh(self):
self.driver.refresh()
logger.info('刷新浏览器')
def get_title(self):
value = self.driver.title
logger.info('获取网页标题,标题是%s'%value)
return value
#元素操作封装
#element_info 看做{'element_name':'用户名输入框','locator_type':'xpath','locator_value':'//input[@name="account"]','timeout':5}
def find_element(self,element_info):#将字符串定位方式转成真正的By. 让每个元素自定义等待
locator_type_name = element_info['locator_type'] #element_info['locator_type']即locator_type的'xpath'
locator_value_info = element_info['locator_value']#element_info['locator_value']即以上注释的'//input[@name="account"]'
locator_timeout = element_info['timeout'] #element_info['timeout']即以上注释的 5
if locator_type_name == 'id': #如果定位类型为以id定位,则使用By.ID方法
locator_type = By.ID
elif locator_type_name == 'class': #如果定位类型为以class定位,则使用By.CLASS_NAME方法
locator_type = By.CLASS_NAME
elif locator_type_name == 'xpath': #如果定位类型为以xpath定位,则使用By.XPATH方法
locator_type = By.XPATH
element = WebDriverWait(self.driver,locator_timeout).until(lambda x:x.find_element(locator_type,locator_value_info))#自定义不同的元素等待不同的时长
logger.info('[%s]元素识别成功'%element_info['element_name']) #login_page会定义element_name属性值
return element
def click(self,element_info):
element = self.find_element(element_info)
element.click()
logger.info('[%s]元素点击操作成功' % element_info['element_name'])
def input(self,element_info,content):
element = self.find_element(element_info)
element.send_keys(content)
logger.info('[%s]元素输入内容' % element_info['element_name'])
import os
import logging
current_path = os.path.dirname(__file__) #获取当前目录路径
log_path = os.path.join(current_path,'../logs/test.log')#日志路径为当前文件夹路径下的test.log
class LogUtils:
def __init__(self,logfile_path=log_path):
self.logfile_path = logfile_path
self.logger = logging.getLogger('Logger')#获取logger对象
self.logger.setLevel(level=logging.INFO)#设置日志级别
file_log = logging.FileHandler(self.logfile_path,encoding='UTF-8')#将日志记录发送到对应路径
formatter = logging.Formatter('%(asctime)s-%(name)s-%(levelname)s-%(message)s')#指定日志输出的具体格式
file_log.setFormatter(formatter)#将formatter绑定到file_log上
self.logger.addHandler(file_log)#将handler添加到对应对象中
def info(self,message):
self.logger.info(message)
def error(self,message):
self.logger.error(message)
logger = LogUtils()
if __name__ == '__main__':
log_utils = LogUtils()#创建log_utils对象
log_utils.info('wanzi',encoding='UTF-8')
V2.0.0:测试数据与代码分离
测试数据:元素识别数据、配置数据(路径、url、邮箱等)、测试用例数据
可以放置在Excel、yaml、MySQL,元素信息数据源设计
1、将元素写入Excel中
2、读取Excel
3、根据其他模块需求组装数据
4、二次封装
element_data_utils.py:将Excel中的元素信息读取到代码中使用
import xlrd
import os
from common.base_page import BasePage
#数据来源于Excel
current_path = os.path.dirname(__name__)
excel_path = os.path.join(current_path,'../element_info_datas/element_infos.xlsx')
class ElementdataUtils:
def __init__(self,page_name,element_path=excel_path):
self.element_path = element_path
self.workbook = xlrd.open_workbook(excel_path)
self.sheet = self.workbook.sheet_by_name(page_name)
self.row_count = self.sheet.nrows
def get_element_info(self):
element_infos ={}
for i in range(1, self.row_count):
element_info = {}
element_info['element_name'] = self.sheet.cell_value(i, 1)
element_info['locator_type'] = self.sheet.cell_value(i, 2)
element_info['locator_value'] = self.sheet.cell_value(i, 3)
element_info['timeout'] = self.sheet.cell_value(i, 4)
element_infos[self.sheet.cell_value(i, 0)] = element_info
return element_infos
if __name__ == '__main__':
# ElementdataUtils('login_page').get_element_info()
elements = ElementdataUtils('login_page').get_element_info()#创建对象
print(elements)
login_page.py优化
import os
from selenium import webdriver
from selenium.webdriver.common.by import By
from common.log_utils import logger
from common.base_page import BasePage
from common.element_data_utils import ElementdataUtils
class LoginPage(BasePage):
def __init__(self,driver):#括号内未写driver时报错
# 父类和子类都有构造方法时,需要用显示方法调用构造函数,先将父类的方法实例化
super().__init__(driver)
elements = ElementdataUtils('login_page').get_element_info()#元素信息
self.username_inputbox = elements['username_inputbox']
self.password_inputbox = elements['password_inputbox']
self.login_button = elements['login_button']
def input_username(self,username):#方法==控件的操作
self.input(self.username_inputbox,username)
def input_password(self,password):
self.input(self.password_inputbox,password)
def click_login(self):
self.click(self.login_button)#先调用basepage中的element方法
if __name__ == '__main__':
driver = webdriver.Chrome()
login_page = LoginPage(driver)
login_page.open_url('http://47.107.178.45/zentao/www/index.php?m=user&f=login')
login_page.set_browser_max()
login_page.input_username('test01')
login_page.input_password('newdream123')
login_page.click_login()
login_page.quit_browser()