基于POM模式设计的UI⾃动化框架
POM即Page-Object-Module,是基于页⾯对象的⾃动化测试设计模式,基于该模式设计的⾃动化框架,直观的把各页⾯元素从代码逻辑中剥离出来,当系统迭代,页⾯元素发⽣更改时,只需要对单独剥离出来的页⾯元素模块进⾏更改,⽽当业务逻辑更改时更改对应的逻辑模块,保证了页⾯元素与逻辑代码的复⽤性,减少了代码的冗余,符和⾯向对象的程序设计思想。
在⼯作中项⽬往往需求变更较⼤,版本迭代周期短,基于POM模式设计的UI⾃动化能够尽可能的提⾼测试代码的复⽤性,因此重构了相关测试代码,使之更能满⾜业务需求。
⼀、项⽬⼯程⽬录
该⾃动化框架实现基于Python+Selenium+Pytest,引⼊单例设计思想;
1.Base_Action主要存放基础操作模块,实现最基础的操作封装;
1.1 base.py模块中定义了BaseAction类,主要封装driver的初始化操作,以及单例设计的实现,UI⾃动化中的单例设计能够有效解决浏览器多开后过⾼占⽤测试计算机内存问题;
func_setDriver :: 实现初始化浏览器操作,使⽤对应浏览器驱动打开⼀个浏览器,在接下来的测试⽤例模块中,每个测试模块测试前都需要调⽤该⽅法;
func_setDriverNone :: 清空初始化后的浏览器数据,每个测试模块测试结束后都需要执⾏该⽅法,为下⼀测试模块重新初始化浏览器做准备;
func_quitDriver :: 进⾏关闭浏览器操作,每个测试模块测试结束后都需要调⽤,关闭浏览器;
func_findElement :: 定位页⾯元素的⽅法封装,默认设置30s超时,此⽅法供接下来的POM⽂件夹中相关页⾯类调⽤实现对应的页⾯元素定位与操作;
根据业务,该BaseAction下可继续添加相关的⽅法,实现对常⽤基础操作的封装供其余模块调⽤;
class BaseAction(object):
_driver = None
@classmethod
def setDriver(cls):
if cls._driver is None:
cls._driver = webdriver.Safari()
cls._driver.maximize_window()
cls._driver.implicitly_wait(5)
return cls._driver
@classmethod
def setDriverNone(cls):
if cls._driver :
cls._driver = None
return cls._driver
@classmethod
def quiteDriver(cls):
return cls.setDriver().quit()
@classmethod
def findElement(cls,driver,by,locator,outTime=30):
try:
print('[Info:Starting find the element "{}" by "{}"!]'.format(locator,by))
element = wd(driver, outTime).until(lambda x : x.find_element(by, locator))
except TimeoutException as t:
print('error: found "{}" timeout!'.format(locator),t)
except NoSuchWindowException as e:
print('error: no such "{}"'.format(locator),e)
except Exception as e:
raise e
else:
print('[Info:Had found the element "{}" by "{}"!]'.format(locator,by))
return element
1.2 get_Params.py中定义了getParams⽅法,主要实现从yaml⽂件中读取数据,存⼊datalist列表中,该测试框架的所有测试数据,以及页⾯元素数据都以yaml⽂件格式统⼀集中存储⽅便后期维护;
def getParams(fileName):
dataList = []
try:
with open(fileName, "r", encoding="UTF-8") as f:
conText = yaml.load_all(f, Loader=yaml.FullLoader)
for i in conText:
dataList.append(i)
except Exception as e:
print('获取{}数据失败!'.format(fileName))
raise e
else:
return dataList
1.3 get_ScreenShot.py中getScreenShot⽅法主要是获取错误截图并存储在对应⽂件夹中,在框架的测试⽤例模块中都有调⽤,实现测试失败时对浏览器进⾏截图并保存;
2.Page_Elements 主要统⼀集中存放各个页⾯的元素,⽅便后期维护,每个页⾯作为⼀个模块独⽴存储,供框架POM中对应页⾯类调⽤实现页⾯元素的定位以及操作;
l :: 集中存储【会员充值管理】页⾯的对应页⾯元素
l :: 集中存储后台⾸页页⾯的对应页⾯元素
l :: 集中存储登录页⾯的对应页⾯元素
要测试的其他页⾯按此⽅法在该⽂件夹下添加即可。
#yaml测试数据
#财务充值页⾯元素对象
inputname_xpath : //*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div[1]/div/div/input
searchbutton_xpath : //*[@id="app"]/div/div[2]/section/div/div[2]/div[1]/div[2]/button[2]/span
resultlistname_xpath : //*[@id="app"]/div/div[2]/section/div/div[3]/div[2]/div[3]/table/tbody/tr/td[4]/div
resultlistphone_xpath : //*[@id="app"]/div/div[2]/section/div/div[3]/div[2]/div[3]/table/tbody/tr/td[6]/div
verbbutton_xpath : //*[@id="app"]/div/div[2]/section/div/div[2]/div[1]/div[2]/button[1]/span
3. Params 对测试数据进⾏集中存储、维护和管理,主要以yml⽂件进⾏存储
l :: 主要存储⽤于测试会员充值管理的测试数据;
l :: 主要存储⽤于登录业务的相关测试⽤例的测试数据;
同样该⽂件夹下的测试数据需要根据测试⽤例的编写进⾏同步维护。
#登录的url
url: dv.democeshi/web_admin/#/login
---
#⽤户登录测试数据
- !!python/tuple
- ceshi001
- 1111111a
- !!python/tuple
- ceshi002
- 111111a
- !!python/tuple
- ceshi003
- 111111b
- !!python/tuple
- ''
- 1111111b
-
!!python/tuple
- ceshi001
- ''
- !!python/tuple
- ''
- ''
---
#⽤户正常登录的账户,⽤于其它业务的测试
- !!python/tuple
- ceshi001
- 1111111a
4. POM 是存储页⾯基类的⽂件夹,把每个页⾯定义成⼀个模块,每个模块定义该页⾯类
accountCharge_page.py :: 会员充值管理页⾯元素对象的操作封装
class AccountCharge(object):
def__init__(self):
self.driver = BaseAction.setDriver()
self.findElement = BaseAction.findElement
def searchName(self,name):
try:
searchNameElement = self.findElement(self.driver, By.XPATH, elements['inputname_xpath']) except Exception as e:
('获取【会员搜索】输⼊框元素失败!')
raise e
else:
return searchNameElement.send_keys(name)
def searchPhone(self,phone):
try:
searchPhoneElement = self.findElement(self.driver, By.XPATH, elements['inputname_xpath']) except Exception as e:
('获取【会员搜索】输⼊框元素失败!')
raise e
else:
return searchPhoneElement.send_keys(phone)
def searchButtonClick(self):
try:
searchButtonElement = self.findElement(self.driver, By.XPATH, elements['searchbutton_xpath']) except Exception as e:
('获取【查询】按钮元素失败!')
raise e
else:
return searchButtonElement.click()
@property
def resultListNameText(self):
try:
resultListNameElement = self.findElement(self.driver, By.XPATH, elements['resultlistname_xpath']) except Exception as e:
('获取结果列表⽤户名元素失败!')
raise e
else:
@property
def resultListPhoneText(self):
try:
resultListPhoneElement = self.findElement(self.driver, By.XPATH, elements['resultlistphone_xpath']) except Exception as e:
('获取结果列表⽤户电话元素失败!')
raise e
python单例模式
else:
def verbButtonClick(self):
try:
verbButtonElement = self.findElement(self.driver, By.XPATH, elements['verbbutton_xpath']) except Exception as e:
('获取【重置】按钮元素失败!')
raise e
else:
return verbButtonElement.click()
home_page.py :: 后台⾸页页⾯元素对象的操作封装
class HomePage(object):
def__init__(self):
self.driver = BaseAction.setDriver()
self.findElement = BaseAction.findElement
def loginImageClick(self):
try:
loginImageElement = self.findElement(self.driver, By.XPATH, elements['loginimage_xpath']) except Exception as e:
('获取⾸页登录⽤户头像失败!')
raise e
else:
return loginImageElement.click()
def quitLoginClick(self):
try:
quitLoginElement = self.findElement(self.driver, By.XPATH, elements['quitlogin_xpath']) except Exception as e:
('获取退出登录元素失败!')
raise e
else:
return quitLoginElement.click()
def indexFinanceClick(self):
try:
indexFinanceElement = self.findElement(self.driver, By.XPATH, elements['indexfinance_xpath']) except Exception as e:
('获取⾸页【财务】元素失败!')
raise e
else:
return indexFinanceElement.click()
def indexChargeBusinessClick(self):
try:
indexChargeBusinessElement = self.findElement(self.driver, By.XPATH, elements['indexcharge_xpath']) except Exception as e:
('获取财务下拉列表中【充值业务】元素失败!')
raise e
else:
return indexChargeBusinessElement.click()
def indexChargeAccountClick(self):
try:
indexChargeAccountElement = self.findElement(self.driver, By.XPATH, elements['indexchargeaccount_xpath']) except Exception as e:
('获取⾸页列表中【会员充值管理】元素失败!')
raise e
else:
return indexChargeAccountElement.click()
login_page.py :: 登录页⾯元素对象的操作封装
class LoginPage(object):
def__init__(self):
self.driver = BaseAction.setDriver()
self.findElement = BaseAction.findElement
def userNameInput(self,username):
try:
self.usernameElement = self.findElement(self.driver, By.XPATH, elements['username_xpath']) except Exception as e:
('获取username对象异常')
raise e
else:
return self.usernameElement.send_keys(username)
def passwordInput(self,password):
try:
self.passwordElement = self.findElement(self.driver, By.XPATH, elements['password_xpath']) except Exception as e:
('获取password对象异常')
raise e
else:
return self.passwordElement.send_keys(password)
def submitButtonClick(self):
try:
self.submitButtonElement = self.findElement(self.driver, By.XPATH, elements['submitbutton_xpath']) except Exception as e:
('获取submit对象异常')
raise e
else:
return self.submitButtonElement.click()
@property
def loginWrongAccountText(self):
try:
self.wrongAccountElement = self.findElement(self.driver, By.XPATH, elements['loginwrongaccount_xpath']) except Exception as e:
('获取登录失败提⽰元素失败!')
raise e
else:
return
@property
def loginUsernameNoneText(self):
try:
self.usernameNoneElement = self.findElement(self.driver, By.XPATH, elements['loginusernamenone_xpath']) except Exception as e:
('获取登录失败提⽰元素失败!')
raise e
else:
return
@property
def loginPasswordNoneText(self):
try:
self.passwordNoneElement = self.findElement(self.driver, By.XPATH, elements['loginpasswordnone_xpath']) except Exception as e:
('获取登录失败提⽰元素失败!')
raise e
else:
return
@property
def loginAccountNoneText(self):
try:
self.accountNontElement = self.findElement(self.driver, By.XPATH, elements['loginaccountnone_xpath']) except Exception as e:
('获取到登录失败提⽰元素失败!')
raise e
else:
return
def userNameInputClear(self):
try:
self.usernameElement = self.findElement(self.driver, By.XPATH, elements['username_xpath'])
except Exception as e:
('获取username对象异常')
raise e
else:
return self.usernameElement.clear()
def passwordInputClear(self):
try:
self.passwordElement = self.findElement(self.driver, By.XPATH, elements['password_xpath'])
except Exception as e:
('获取password对象异常')
raise e
else:
return self.passwordElement.clear()
同样该POM中需要把测试的每个页⾯元素对象做对应的封装,供business调⽤,完成业务逻辑的代码实现
现总结⼀下前⾯介绍的⼏个模块的数据流:
在整个框架中,POM承担起了业务逻辑与页⾯基础操作的桥梁,直接对接下来的Business中的业务模块服务5. Business 主要集中维护整个被测试系统的业务操作逻辑
5.1 例:loginAc.py :: 定义相关的登录操作
class LoginAction(BaseAction):
def__init__(self,url):
self.url = url
self.driver = BaseAction.setDriver()
(url)
@classmethod
def loginWrongAccount(cls):
failText = LoginPage().loginWrongAccountText
loging.logger.info('⽤错误的登录帐号登录_获取到的失败提⽰:{}'.format(failText))
return failText
@classmethod
def loginUsernameNone(cls):

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。