從0到1搭建測試自動化框架

我們在做自動化測試過程中,需要對我們的自動化用例,以及代碼進行管理,使其更加結構化,模塊化。從而更方便擴展以及維護。好的測試框架,讓自動化更加省時省力。

當我們的自動化用例和代碼寫得多的時候,需要用一種方式來管理。就像我們建房子,當建的房子不是高層的時候,可以用一磚一瓦來建設。當建摩天大廈時,這種方式不牢靠,且效率及其低下。現在建築業都是用框架式來建設,然後填充,最後裝修。

軟體工程也是如此。

小傑是一名軟體測試工程師。每天的工作就是理解產品需求,寫測試用例,以及手工執行測試用例。他希望減少一遍又一遍的重複勞動,於是就自學了web自動化。

第一次寫出的用例如下:

from selenium import webdriverfrom selenium.webdriver.support.ui import WebDriverWaitdef open_home(): driver = webdriver.Firefox() driver.get("https://testerhome.com/") driver.implicitly_wait(5) driver.find_element_by_link_text("Sign In").click() driver.implicitly_wait(3) username = WebDriverWait(driver, 5).until(lambda x: x.find_element_by_id("user_login")) username.clear() username.send_keys("XXX") password = WebDriverWait(driver, 5).until(lambda x: x.find_element_by_id("user_password")) password.clear() password.send_keys("XXX") driver.find_element_by_name("commit").click() driver.implicitly_wait(3) driver.quit()if __name__ == "__main__": open_home()

他很激動,雖然是一小步,畢竟自動化起來了。他滿心歡喜的show給測試老鳥小明看。

小明當場給他澆了一盆冷水。 「你這都不能算自動化測試用例,連個驗證點都沒有。」

於是在小明的指點下,通過改進,終於完成了一版像那麼回事自動化用例。

import unittestfrom selenium import webdriverfrom selenium.webdriver.support.ui import WebDriverWaitclass Login(unittest.TestCase): def setUp(self): self.driver = webdriver.Firefox() self.driver.implicitly_wait(5) self.base_url = "https://testerhome.com/" def test_open_home(self): driver = self.driver driver.get(self.base_url) driver.implicitly_wait(5) driver.find_element_by_link_text("Sign In").click() driver.implicitly_wait(3) username = WebDriverWait(driver, 5).until(lambda x: x.find_element_by_id("user_login")) username.clear() username.send_keys("beerbox") password = WebDriverWait(driver, 5).until(lambda x: x.find_element_by_id("user_password")) password.clear() password.send_keys("Good_Luck888") driver.find_element_by_name("commit").click() driver.implicitly_wait(3) self.assertIn("TesterHome",driver.title) def tearDown(self): self.driver.quit()if __name__ == "__main__": suite = unittest.TestSuite() suite.addTest(Login(test_open_home)) unittest.TextTestRunner().run(suite)

小傑很激動,想這回你小明應該表揚下我了吧。你看我驗證點也有了,還有一個這麼漂亮的報告。

誰知小明僅僅對小傑的進步表示了讚賞,但仍然對小傑的代碼不滿意。

「你這像錄製的代碼。你這寫一個用例容易,如果寫多個用例,維護起來非常麻煩。你需要一個框架來優化你的代碼,我建議你學學page object的思想」。

於是乎,小傑積極搗鼓,優化版也成型了。

cases/login.py

import unittestfrom frame3.pages.loginpage import login_pageclass caselogin(unittest.TestCase): def setUp(self): self.username = "XXX" self.password = "XXX" self.login = login_page() def test_login_with_correct_account(self): 檢查正確賬號密碼能登陸 self.login.login_action(self.username,self.password) self.assertIn("TesterHome",self.login.driver.title) def tearDown(self): self.login.driver.quit()

pages/login_page.py

from selenium.webdriver.common.by import Byfrom frame3.basepage import pageclass login_page(page): # 定位器,通過元素屬性定位元素對象 username_loc = (By.ID, "user_login") password_loc = (By.ID, "user_password") submit_loc = (By.NAME, "commit") # 調用send_keys對象,輸入用戶名 def input_username(self, username): self.find_element(*self.username_loc).send_keys(username) # 調用send_keys對象,輸入密碼 def input_password(self, password): self.find_element(*self.password_loc).send_keys(password) # 調用send_keys對象,點擊登錄 def click_submit(self): self.find_element(*self.submit_loc).click() def login_action(self,username,password): self.open(self.base_url) self.input_username(username) self.input_password(password) self.click_submit()

BasePage.py

from selenium.webdriver.support.wait import WebDriverWaitfrom selenium import webdriverclass page(object): def __init__(self): self.driver = webdriver.Firefox() self.base_url = "https://XXX/account/sign_in" # 打開頁面,校驗頁面鏈接是否載入正確 def _open(self, url): # 使用get打開訪問鏈接地址 self.driver.get(url) self.driver.maximize_window() # # # 使用assert進行校驗,打開的鏈接地址是否與配置的地址一致。調用on_page()方法 # assert self.on_page(pagetitle), u"打開開頁面失敗 %s" % url # 重寫元素定位方法 def find_element(self, *loc): # return self.driver.find_element(*loc) try: WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element(*loc).is_displayed()) return self.driver.find_element(*loc) except: print(u"%s 頁面中未能找到 %s 元素" % (self, loc)) # 重寫switch_frame方法 def switch_frame(self, loc): return self.driver.switch_to.frame(loc) # 定義open方法,調用_open()進行打開鏈接 def open(self,url): self._open(url) # 使用current_url獲取當前窗口Url地址,進行與配置地址作比較,返回比較結果(True False) def on_page(self, pagetitle): return pagetitle in self.driver.title # 定義script方法,用於執行js腳本,範圍執行結果 def script(self, src): self.driver.execute_script(src) # 重寫定義send_keys方法 def send_keys(self, loc, vaule, clear_first=True, click_first=True): try: loc = getattr(self, "_%s" % loc) if click_first: self.find_element(*loc).click() if clear_first: self.find_element(*loc).clear() self.find_element(*loc).send_keys(vaule) except AttributeError: print(u"%s 頁面中未能找到 %s 元素" % (self, loc))

小明對此版本還算滿意,表示這裡面hard code太多,小傑在小明的幫助下,終於搭建了一款自己還比較滿意的框架。

作者簡介:

Snake, 人稱安蜀黍,專職軟體測試10幾年,測試界的老司機。

更多精彩,請關注微信公眾號:python愛好部落

推薦閱讀:

在Selenium Webdriver中使用XPath Contains、Sibling函數定位
python selenium2自動化測試系列電子書

TAG:自動化測試 | Python | 軟體測試 |