python+selenium自动化测试21

🔥《一头扎进》系列之Python+Selenium框架实战篇4-价值好几K的框架,呵!这个框架有点意思啊!!!

1.简介

前面文章,我们实现了框架的一部分功能,包括日志类和浏览器引擎类的封装,今天我们继续封装一个基类和介绍如何实现POM。关于基类,是这样定义的:把一些常见的页面操作的selenium封装到base_page.py这个类文件,以后每个POM中的页面类,都继承这个基类,这样每个页面类都有基类的方法,这个我们会在这篇文章由宏哥实现。

2.项目层级结构

1.上一篇中我们已经创建好了项目层级结构,具体项目层级结构如下图。这里不再赘述,相关文件也如下:

1232840-20191219113551572-1602006466.png

3.定位和截图类封装

1.在实现封装基类里,我们实现了元素八大方式的定位和截图类封装。

2.基类base_page.py的具体实现代码,这里就封装了几个常用方法,其他方法,你自己去练习封装下。

3.1代码实现

1232840-20191220142652608-958817746.png

3.2参考代码
#-*-coding:utf-8-*-

#1.先设置编码,utf-8可支持中英文,如上,一般放在第一行

#2.注释:包括记录创建时间,创建人,项目名称。
'''
Createdon 2016-02-08
@author:北京-宏哥QQ交流群:705269076
Project:《《一头扎进》系列之Python+Selenium框架设计篇4-价值好几K的框架,不看别后悔,过时不候
'''

#3.导入模块

importtime
fromselenium.common.exceptionsimportNoSuchElementException
importos.path
fromautomation_framework_demo.framework.loggerimportLogger

#createaloggerinstance
logger=Logger(logger="BasePage").getlog()

classBasePage(object):
"""
定义一个页面基类,让所有页面都继承这个类,封装一些常用的页面操作方法到这个类
"""
def__init__(self,driver):
self.driver=driver

#quitbrowserandendtesting
defquit_browser(self):
self.driver.quit()

#浏览器前进操作
defforward(self):
self.driver.forward()
logger.info("Clickforwardoncurrentpage.")

#浏览器后退操作
defback(self):
self.driver.back()
logger.info("Clickbackoncurrentpage.")

#隐式等待
defwait(self,seconds):
self.driver.implicitly_wait(seconds)
logger.info("waitfor%dseconds."%seconds)

#点击关闭当前窗口
defclose(self):
try:
self.driver.close()
logger.info("Closingandquitthebrowser.")
exceptNameErrorase:
logger.error("Failedtoquitthebrowserwith%s"%e)

#保存图片
defget_windows_img(self):
"""
在这里我们把file_path这个参数写死,直接保存到我们项目根目录的一个文件夹.\Screenshots下
"""
file_path=os.path.dirname(os.path.abspath('.'))+'/screenshots/'
rq=time.strftime('%Y%m%d%H%M',time.localtime(time.time()))
screen_name=file_path+rq+'.png'
try:
self.driver.get_screenshot_as_file(screen_name)
logger.info("Hadtakescreenshotandsavetofolder:/screenshots")
exceptNameErrorase:
logger.error("Failedtotakescreenshot!%s"%e)
self.get_windows_img()

#定位元素方法
deffind_element(self,selector):
"""
这个地方为什么是根据=>来切割字符串,请看页面里定位元素的方法
submit_btn="id=>su"
login_lnk="xpath=>//*[@id='u1']/a[7]"#百度首页登录链接定位
如果采用等号,结果很多xpath表达式中包含一个=,这样会造成切割不准确,影响元素定位
:paramselector:
:return:element
"""
element=''
if'=>'notinselector:
returnself.driver.find_element_by_id(selector)
selector_by=selector.split('=>')[0]
selector_value=selector.split('=>')[1]
print(selector_value)
ifselector_by=="i"orselector_by=='id':
try:
element=self.driver.find_element_by_id(selector_value)
logger.info("Hadfindtheelement\'%s\'successful"
"by%sviavalue:%s"%(element.text,selector_by,selector_value))
exceptNoSuchElementExceptionase:
logger.error("NoSuchElementException:%s"%e)
self.get_windows_img()#takescreenshot
elifselector_by=="n"orselector_by=='name':
element=self.driver.find_element_by_name(selector_value)
elifselector_by=="c"orselector_by=='class_name':
element=self.driver.find_element_by_class_name(selector_value)
elifselector_by=="l"orselector_by=='link_text':
element=self.driver.find_element_by_link_text(selector_value)
elifselector_by=="p"orselector_by=='partial_link_text':
element=self.driver.find_element_by_partial_link_text(selector_value)
elifselector_by=="t"orselector_by=='tag_name':
element=self.driver.find_element_by_tag_name(selector_value)
elifselector_by=="x"orselector_by=='xpath':
try:
element=self.driver.find_element_by_xpath(selector_value)
logger.info("Hadfindtheelement\'%s\'successful"
"by%sviavalue:%s"%(element.text,selector_by,selector_value))
exceptNoSuchElementExceptionase:
logger.error("NoSuchElementException:%s"%e)
self.get_windows_img()
elifselector_by=="s"orselector_by=='selector_selector':
element=self.driver.find_element_by_css_selector(selector_value)
else:
raiseNameError("Pleaseenteravalidtypeoftargetingelements.")
print(element)
returnelement

#输入
deftype(self,selector,text):
el=self.find_element(selector)
el.clear()
try:
el.send_keys(text)
logger.info("Hadtype\'%s\'ininputBox"%text)
exceptNameErrorase:
logger.error("Failedtotypeininputboxwith%s"%e)
self.get_windows_img()

#清除文本框
defclear(self,selector):

el=self.find_element(selector)
try:
el.clear()
logger.info("Cleartextininputboxbeforetyping.")
exceptNameErrorase:
logger.error("Failedtoclearininputboxwith%s"%e)
self.get_windows_img()

#点击元素
defclick(self,selector):

el=self.find_element(selector)
try:
el.click()
logger.info("Theelement\'%s\'wasclicked."%el)
exceptNameErrorase:
logger.error("Failedtoclicktheelementwith%s"%e)

#或者网页标题
defget_page_title(self):
logger.info("Currentpagetitleis%s"%self.driver.title)
returnself.driver.title

@staticmethod
defsleep(seconds):
time.sleep(seconds)
logger.info("Sleepfor%dseconds"%seconds)

4.pageObjects文件夹下相关代码

1.页面对象中,百度主页的元素定位和简单的操作函数,页面类主要是元素定位和页面操作写成函数,供测试类调用。

baidu_homepage.py

4.1代码实现

1232840-20191220141229591-491080604.png

4.2参考代码
#-*-coding:utf-8-*-

#1.先设置编码,utf-8可支持中英文,如上,一般放在第一行

#2.注释:包括记录创建时间,创建人,项目名称。
'''
Createdon 2016-02-08
@author:北京-宏哥QQ交流群:705269076
Project:《《一头扎进》系列之Python+Selenium框架设计篇4-价值好几K的框架,不看别后悔,过时不候
'''
#3.导入模块

fromautomation_framework_demo.framework.base_pageimportBasePage

classHomePage(BasePage):
input_box="id=>kw"
search_submit_btn="xpath=>//*[@id='su']"

#百度新闻入口
#news_link="xpath=>//*[@id='u1']/a[@name='tj_trnews']"
news_link="xpath=>//*[@id='u1']/a[@name='tj_trnews']"

deftype_search(self,text):
self.type(self.input_box,text)

defsend_submit_btn(self):
self.click(self.search_submit_btn)

defclick_news(self,):
self.click(self.news_link)
self.sleep(2)

这里注意下元素定位写法,=>和base_page.py中find_element()方法元素定位切割有关系,网上有些人写根据逗号切割或者等号切割,在实际使用xpath定位,发现单独逗号或者单独等号切割都不精确,造成元素定位失败。

5.测试类的写法举例

1.新建一个测试类baidu_search1.py。

baidu_search1.py

5.1代码实现

1232840-20191220142652608-958817746.png

5.2参考代码
#-*-coding:utf-8-*-

#1.先设置编码,utf-8可支持中英文,如上,一般放在第一行

#2.注释:包括记录创建时间,创建人,项目名称。
'''
Createdon 2016-02-08
@author:北京-宏哥QQ交流群:705269076
Project:《《一头扎进》系列之Python+Selenium框架设计篇4-价值好几K的框架,不看别后悔,过时不候
'''

#3.导入模块

importtime
importunittest
fromautomation_framework_demo.framework.browser_engineimportBrowserEngine
fromautomation_framework_demo.pageobjects.baidu_homepageimportHomePage


classBaiduSearch(unittest.TestCase):


defsetUpClass(cls):
"""
测试固件的setUp()的代码,主要是测试的前提准备工作
:return:
"""
browse=BrowserEngine(cls)
cls.driver=browse.open_browser(cls)


deftearDownClass(cls):
"""
测试结束后的操作,这里基本上都是关闭浏览器
:return:
"""
cls.driver.quit()

deftest_baidu_search(self):
"""
这里一定要test开头,把测试逻辑代码封装到一个test开头的方法里。
:return:
"""
#self.driver.find_element_by_id('kw').send_keys('selenium')
#time.sleep(1)
homepage=HomePage(self.driver)
homepage.type_search('selenium')#调用页面对象中的方法
homepage.send_submit_btn()#调用页面对象类中的点击搜索按钮方法
time.sleep(2)
homepage.get_windows_img()#调用基类截图方法
print(self.driver.title)
try:
assert('selenium'inHomePage.get_page_title(self))
print('TestPass.')
exceptExceptionase:
print('TestFail.',format(e))

deftest_search2(self):
homepage=HomePage(self.driver)
homepage.type_search('python')#调用页面对象中的方法
homepage.send_submit_btn()#调用页面对象类中的点击搜索按钮方法
time.sleep(2)
homepage.get_windows_img()#调用基类截图方法


if__name__=='__main__':
unittest.main()
5.3运行结果

运行代码后,控制台打印如下图的结果

1232840-20191220142933132-1251851631.png

5.4代码说明
homepage=HomePage(self.driver)

上面这行代码要注意,意思是:到一个页面,第一件事情是初始化这个页面的一个页面对象实例。注意,一定要带self.driver,不然会报错,这个self.driver,可以这样理解:在当前测试类里面,self.driver是来自浏览器引擎类中方法得到的,在初始化一个页面对象的时候,也把这个来自浏览器引擎类的driver给赋值给当前的页面对象,这样,才能执行页面对象或者基类里面的相关driver方法。写多了selenium的自动化脚本,你会明白,最重要的是保持前后driver的唯一性。

5.5生成图片

1.测试结果:会在logs文件夹生成一个日志文件,也会在screenshots文件夹生成一个png图片。日志看过了,这里我们看一下图片

1232840-20191220143116447-1767610017.png

2.图片内容如下图:

1232840-20191220143153511-1340853207.png

6.小结

好了,今天的分享就到这里吧!!!谢谢各位的耐心阅读。有问题加群交流讨论


扫码关注公众号,更多干货秒得到

  目录