Python+Selenium框架設計篇之7-進一步實現POM和可能遇到問題解決辦法
本文進一步演示POM的具體實現,前面POM只是一個頁面,一個測試指令碼,現在我們要實現三個頁面,兩個測試指令碼。在pageobjects包下,我新建了2個頁面物件:百度新聞首頁,百度體育新聞首頁,具體檔案結構如下圖,其他和之前專案層級結構保持不變。
百度首頁頁面類程式碼(baidu_homepage.py),定義了百度新聞的入口
百度新聞首頁的頁面類程式碼(baidu_news_home.py),定義了體育新聞入口# coding=utf-8 from framework.base_page import BasePage class HomePage(BasePage): input_box = "id=>kw" search_submit_btn = "xpath=>//*[@id='su']" # 百度新聞入口 news_link = "xpath=>//*[@id='u1']/a[@name='tj_trnews']" def type_search(self, text): self.type(self.input_box, text) def send_submit_btn(self): self.click(self.search_submit_btn) def click_news(self): self.click(self.news_link) self.sleep(2)
# coding=utf-8
from framework.base_page import BasePage
class NewsHomePage(BasePage):
# 點選體育新聞入口
sports_link = "xpath=>//*[@id='channel-all']/div/ul/li[5]/a"
def click_sports(self):
self.click(self.sports_link)
self.sleep(2)
百度體育新聞頁面類程式碼(news_sports_home.py)
測試類程式碼(test_nba_news_view.py)# coding=utf-8 from framework.base_page import BasePage class SportNewsHomePage(BasePage): # NBA入口 nba_link = "xpath=>//*[@id='channel-submenu']/div/span[2]/a[1]" def click_nba_link(self): self.click(self.nba_link) self.sleep(2)
測試步驟大概是:百度首頁點選新聞連結-進入新聞主頁,點選體育-進入體育新聞主頁,點選NBA-進入NBA頁面-其他後續指令碼操作。為什麼要採用這樣的步驟呢,幹嘛不直接driver.get('nba的連結')?因為我們就是要利用POM的思想去寫我們測試指令碼,才有上面的測試步驟。
通過上面的# coding=utf-8 import time import unittest from framework.browser_engine import BrowserEngine from pageobjects.baidu_homepage import HomePage from pageobjects.baidu_news_home import NewsHomePage from pageobjects.news_sport_home import SportNewsHomePage class ViewNBANews(unittest.TestCase): def setUp(self): browse = BrowserEngine(self) self.driver = browse.open_browser(self) def tearDown(self): self.driver.quit() def test_view_nba_views(self): # 初始化百度首頁,並點選新聞連結 baiduhome = HomePage(self.driver) baiduhome.click_news() # 初始化一個百度新聞主頁物件,點選體育 newshome = NewsHomePage(self.driver) newshome.click_sports() #初始化一個體育新聞主頁,點選NBA sportnewhome = SportNewsHomePage(self.driver) sportnewhome.click_nba_link() sportnewhome.get_windows_img() if __name__ == '__main__': unittest.main()
指令碼,進入一個新的頁面,就要初始化這個頁面的物件,然後才能呼叫這個頁面相關的方法,driver這個例項物件在不同頁面之間切換,這個就是POM的核心內容。我們來測試執行這個類看看,結果報錯。
StaleElementReferenceException: Message: stale element reference: element is not attached to the page document
原因分析:
字面意思是說,頁面元素不在當前頁面物件沒有載入到頁面,就不能找到元素,不能進行點選,這個報錯發生在,百度新聞首頁點選體育這行程式碼裡。
由於我們的driver這個例項物件在不同的頁面裡切換,可能造成了這個報錯,這個問題在python+selenium遇到過,java+selenium沒有遇到,國外網站,有人建議,既然找不到這個元素,那麼在腳本里,就直接driver.find_elemen(xpath)再找一次。也就是說,可能我們利用頁面物件方法,點選不了這個體育連結,那麼我們直接在腳本里通過find_element方法去定位體育這個元素,然後再點選。這個也算是一個bug,目前暫時沒有更好辦法解決,不知道以後chromedriver.exe升級會不會解決這個問題不好說。
我們調整下我們測試類程式碼,新增find_element()語句
# coding=utf-8
import time
import unittest
from framework.browser_engine import BrowserEngine
from pageobjects.baidu_homepage import HomePage
from pageobjects.baidu_news_home import NewsHomePage
from pageobjects.news_sport_home import SportNewsHomePage
class ViewNBANews(unittest.TestCase):
def setUp(self):
browse = BrowserEngine(self)
self.driver = browse.open_browser(self)
def tearDown(self):
self.driver.quit()
def test_view_nba_views(self):
# 初始化百度首頁,並點選新聞連結
baiduhome = HomePage(self.driver)
#baiduhome.click_news()
self.driver.find_element_by_xpath("//*[@id='u1']/a[@name='tj_trnews']").click()
# 初始化一個百度新聞主頁物件,點選體育
newshome = NewsHomePage(self.driver)
#self.driver.refresh()
#newshome.click_sports()
self.driver.find_element_by_xpath("//*[@id='channel-all']/div/ul/li[5]/a").click()
#初始化一個體育新聞主頁,點選NBA
sportnewhome = SportNewsHomePage(self.driver)
#sportnewhome.click_nba_link()
self.driver.find_element_by_xpath("//*[@id='channel-submenu']/div/span[2]/a[1]").click()
sportnewhome.get_windows_img()
if __name__ == '__main__':
unittest.main()
其實,我們之前頁面物件呼叫點選相關元素進入下一個頁面,在回放指令碼是看起作用了,但是就是報錯,所以這裡,只好在三個地方點選進入下一個頁面的時候,採用self.driver.find_element()方法。這個和我們POM的思想,頁面物件只寫元素定位和相關方法,指令碼類一般不寫頁面元素定位相矛盾,是吧。也許未來能解決這個問題,或者你接受當前這個方法,或者,你單獨寫一個進入到NBA的類,例如直接driver.get()然後封裝靜態類,當做其他NBA頁面指令碼的測試韌體引入,這樣也可以。
實際專案指令碼開發也應該有一些公共方法封裝成模組或者靜態類,例如,把登入事件寫成靜態類,第二個用例是收藏一篇文章,收藏的測試前提就是登入,所以在收藏類的測試韌體中的setUp()裡就呼叫登入的模組指令碼。同樣,你寫登入的事件,可能封裝了瀏覽器的呼叫。具體問題要具體分析,實際指令碼開發過程要隨機應變,一種方法實現起來困難,就想辦法繞過去,這個是自動化測試工程師要一直面臨的挑戰。