2019 Selenium3與Python3實戰開發Web自動化測試框架(一)

說明:該篇博客是博主一字一碼編寫的,實屬不易,請尊重原創,謝謝大家!

目錄

一丶敘述

二丶環境搭建

三丶項目實戰中PO模型的設計與封裝


一丶敘述

1.項目介紹

項目分爲九部分:基礎項目實戰PageObjectUnittest數據驅動關鍵字驅動行爲驅動日誌模塊持續繼承源碼管理

實戰基礎:[{"Selenium3":["環境搭建","基礎API使用"]},"如何破解驗證碼","基礎函數的封裝"]

分層自動化:["分層設計思想","分層設計實戰","分層case編寫","流程調節"]

Unittest與PO結合:["Unittest的使用","assert斷言","HTMLTestRunner","如何批量管理case","失敗截圖處理","項目結合"]

數據驅動的使用:["數據驅動基礎","PO中引入數據驅動","文件實現數據驅動","項目中引入數據驅動"]

關鍵字模型從設計到開發:{"實現持續集成":["關鍵字模型設計","操作類設計封裝","關鍵字模型實現","流程梳理"]}

行爲驅動從設計到開發:["環境搭建","行爲驅動分析","行爲驅動case編寫","行爲驅動和PO"]

日誌模塊項目中的使用:["日誌模塊介紹","日誌簡單應用","保存日誌","項目中使用日誌"]

持續集成:["持續集成的使用","使用郵件進行通知","定時執行工程"]

源碼管理:["git環境的搭建","倉庫的運用","創建分支","代碼的克隆","實現更好的管理"]

2.項目效果展示

  • 首先博主先展示一個比較low的HTMLTestRunner測試報告

  • 話不多說高大上的HTMLTestRunner測試報告

  •  點擊詳情後,查看對應測試用例結果

  • 點擊失敗,可查看測試用例失敗的詳情錯誤信息

  • 鼠標放在餅形圖上可查看測試結果比列數據

  • 最後的測試報告則是通過持續集成Jenkins來向目標郵箱發送測試報告

 

二丶環境搭建

 1.selenium環境搭建

  • Selenium工作原理

  • 需要的環境有Client丶Driver丶Brower
  • Client端使用Pycharm進行代碼編寫開發語言爲python3
  • Driver端使用谷歌瀏覽器的ChromeDriver

2.環境搭建實戰

  • python3.x版本的安裝,因博主早就安裝了所以這裏不演示

  • 安裝項目的虛擬環境

  • 在以上創建的webtest_py3環境中安裝selenium

  • 在Pycharm中新建一個名爲SeleniumPython的項目,項目環境爲webtest_py3

  • 創建項目成功後,在項目根目錄下創建cdtaogang_selenium目錄,然後該目錄下創建start_browser.py文件,如下

  • 在start_browser文件中編寫如下代碼啓動chrome瀏覽器
from selenium import webdriver
driver = webdriver.Chrome()
  • 運行start_browser文件,則提示如下錯誤信息

  • 出現以上錯誤是因爲selenium不知道你的瀏覽器的位置,所以需要安裝chromedriver來作爲中間件來操作你的瀏覽器,首先需要知道你的谷歌瀏覽器的版本信息,點擊瀏覽器中的幫助——關於Google Chrome來查看版本信息

  • 緊接着將下載好的chromedriver.exe文件拷貝到你的項目使用的python安裝目錄即可

  • 重新運行代碼,成功打開谷歌瀏覽器

  • 通過driver對象的get方法,在方法中輸入url地址,運行代碼則打開谷歌瀏覽器並且訪問目標url地址

3.需求分析及用例設計

  • 對樂學網站的註冊功能進行分析,如下圖所示

  • 創建測試需求分析文檔

  • 創建測試用例文檔

  • 測試用例文檔中的id元素的值,通過瀏覽器檢查即可看到

4.註冊頁面結構分析

  • 在網站的註冊頁面,點擊檢查元素,通過選擇器來選擇頁面內容查看該頁面內容對應的html標籤,發現整個註冊窗口分爲兩個部分,第一部分就是如下圖所示的login-tab標籤容器,第二部分就是login-main輸入框部分所在的容器

  • 查看login-main容器下的輸入框容器,都是在form表單中進行提交到服務器的

  • 在form表單中的div表示每個輸入框以及提交按鈕的容器,查看每個div對應的頁面內容

  • 還可以輸入js代碼來獲取你想要獲取的html標籤元素

5.啓動不同瀏覽器

說明:在實際自動化測試工作中,肯定不會只打開一種瀏覽器

  • 前面已經對谷歌瀏覽器Chrome進行了打開併成功訪問百度,接下來是打開IE瀏覽器,首先需要跟之前Chrome瀏覽器一樣需要下載driver插件,進入http://selenium-release.storage.googleapis.com/index.html地址下載IE的IEDriverServer,需要注意的是IEDriverServer的版本要與你安裝的Selenium版本一致不然會出錯,然後將下載好的IEDriverServer.exe文件放在項目所在的python安裝目錄中,如果你的windows版本爲10則需要去官網下載MicrosoftWebDriver.exe

  • 然後在start_browser文件中去調用Ie的接口方法打開瀏覽器,需要注意的是win10是調用Edge方法

  • 然後在代碼中調用Firefox方法,成功的打開火狐瀏覽器並訪問百度

6.使用title_contains檢查頁面是否正確

  • 通過selenium打開瀏覽器並訪問測試的網站地址,根據頁面的元素以及網頁的title標題來判斷是否成功的打開目標地址

  • 通過從selenium.webdriver.support包中導入expected_conditions,再使用expected_conditions模塊中的title_contains方法來判斷目標地址title中是否包含了"註冊"字段,查看打印的結果說明title中包含了"註冊"字段

7.使用不同方式進行定位

  • 註冊表單中的郵箱地址通過class選擇器定位

driver.find_element_by_class_name("form-control input-lg").send_keys("[email protected]")
  •  註冊表單中的用戶名通過id選擇器定位

driver.find_element_by_id("register_nickname").send_keys("cdtaogang")
  • 註冊表單中的密碼通過name屬性來進行定位

driver.find_element_by_name("password").send_keys("111111")
  • 註冊表單中的驗證碼通過xpath來進行定位

driver.find_element_by_xpath('//*[@id="captcha_code"]').send_keys("xrfdw")
  • 運行代碼,則出現如下錯誤提示

  • 導致以上錯誤的原因是第一存在書寫不規範傳遞的class name中存在空格,第二主要是該class name的值不唯一

  • 解決方法就是:要麼不使用class name進行定位,要麼就在當前class name上增加父級的class name來保證數據唯一

driver.find_element_by_class_name("controls").find_element_by_class_name("form-control").send_keys("[email protected]")
  • 重新運行代碼,成功的訪問註冊頁面並自動填寫註冊表單的數據

  • 動圖顯示自動輸入表單數據

  • 其實代碼是有問題的,之所以能成功輸入郵箱地址丶用戶名丶密碼以及驗證碼,那是因爲博主剛好是在表單第一個div容器郵箱地址選擇了class name進行查找的,因爲按照父級div class="controls" 子級 div class="form-control input-lg"的標籤不是唯一的

  • 所以正確的代碼因該是通過find_elements_by_class_name獲取class name 爲controls的所有結果集,取結果集的第一個元素,爲什麼是第一個元素因爲郵箱地址就是表單中的第一個元素,然後從結果中找到class name爲form-control的標籤,這纔是正確的代碼

8.如何使用Expected_conditions判斷元素是否可見

  • 需要使用expected_conditions模塊也就是ec中的visibility_of_element_located來檢驗元素的可見性,然後再selenium.webdriver.support包下的wait模塊中導入WebDriverWait這個類,通過實例化這個類後調用其until方法來判斷元素是否存在,存在的話代碼繼續運行不存在則返回false
element = driver.find_element_by_class_name("controls")
result = ec.visibility_of_element_located(element)
WebDriverWait(driver, 1).until(result)
  • 運行代碼,提示如下錯誤

  • 解決方法:from selenium.webdriver.common.by import By導入By這個類,通過這個類的CLASS_NAME屬性與查找元素class name的值"controls"來形成元組傳遞給visibility_of_element_located進行構造

  • 到現在這一步,如果有朋友發現自己的電腦比較卡的話,那是因爲不斷的運行程序,那麼就會一直在windows任務中創建 chromedriver.exe的計劃,這樣導致自己電腦越來越卡;但是博主的電腦沒有感受到任何的卡頓,可能是內存性能比較高吧

  • 解決方法就是在代碼中進行close關閉driver
driver.close()

9.Expected_conditions源碼分析

  • 在Pycharm中按住Ctrl後鼠標左鍵點擊即可進入源碼查看,通過源碼的註釋以及返回值包括核心代碼來查看整個實現過程,也能看出框架的核心的代碼,如下我們之前調用的title_is這個方法源碼中就是拿傳遞的title與driver中的title進行對比,返回Boolean類型

  • 還有就是實例化visibility_of_element_located類時,傳遞的locator,來判斷元素是否存在不存在出現異常則返回False

10.輸入註冊用戶名字及獲取用戶信息

  • 在註冊頁面的郵箱地址一欄,通過代碼獲取郵箱地址欄標籤中placeholder得值,也就是“填寫你常用的郵箱作爲登錄帳號”這句話,首先是獲取郵箱所在的element元素,通過get_attribute方法來獲取該標籤中想要獲取的元素,代碼如下
email_element = driver.find_element_by_id("register_email")
print(email_element.get_attribute("placeholder"))

  • 通過郵箱地址element元素send_keys方法向input框中輸入郵箱地址,然後再通過get_attribute方法來獲取輸入的value屬性值,需要注意的是當你input框中輸入數據時,檢查元素中並沒有input框中的數據字段,當沒有屬性值的則默認輸入value進行獲取,代碼如下
email_element.send_keys("[email protected]")
print(email_element.get_attribute("value"))

  • 運行代碼,查看結果中成功打印出郵箱地址input標籤中的placeholder的值以及input框中的內容

11.如何生成用戶名

  • 使用python內置的random模塊進行郵箱地址的生成

12.如何解決驗證碼思路

  • 在公司內部測試中可以通過登錄成功後的cookie狀態來進行登錄忽略驗證碼,還可以公司開發設定一個萬能的驗證碼以及取消驗證碼,在這裏我們通過將生成的二維碼圖片通過selenium driver中的sava方法進行保存後,使用pytesseract讀圖片中的驗證碼進行解析

13.如何解決驗證碼代碼實戰

  • 驗證碼的圖片是需要我們去獲取的,只能定位頁面中驗證碼的座標來將圖片裁剪下來進行識別,爲什麼不能通過驗證碼的url地址來進行圖片的獲取,因爲每當訪問或者刷新圖片驗證碼的地址會導致驗證碼的更改,所以必須要取頁面上用戶看到的驗證碼圖片,首先獲取頁面中驗證碼的座標,並通過save_screenshot方法將頁面保存下來

  • 查看F:/selenium_image/captcha.png文件,並打開此圖片

  • 緊接着需要獲取驗證碼的高度和寬度,然後通過python的pillow庫中image對象的corp對下載到F:/selenium_image/captcha.png的圖片進行裁剪,將裁剪下的圖片保存到F:/selenium_image/captcha_1.png文件

  • 打開F:/selenium_image/captcha_1.png圖片,成功截取到驗證碼圖片

14.使用pytesseract識別圖片中得問題

  • 首先需要在項目環境中安裝pytesseract庫

  • 然後在項目目錄下常見read_image_code.py文件,在文件中編寫如下代碼,並對之前截取的captcha_1.png圖片進行讀取打印出圖片中的文字,從打印結果看很不理想無法讀取,原因是pytesseract庫讀取圖片中的文字信息是要求整潔清晰並且有規則無干擾項

15.showapiRequest解決圖片驗證碼識別

  • 目前來說要能識別圖片驗證並且有很高的的效率要麼就是自己去開發一個失敗圖片驗證碼的框架或者工具,這個難度比較高,要麼就是去調用別人公司開發出來的api進行使用,博主在https://www.showapi.com/ 中去下載其python語言下的sdk工具

  • 需要註冊用戶後,選擇圖片驗證碼識別,然後進行購買使用套餐即可,價格也很便宜

  • 購買成功以後在,我的訂單中則出現瞭如下的計量,可以看到使用每個驗證碼接入點的配量,只需要0.1元

  • 在我的資源中則看到自己購買的資源包

  • 緊接着在網站中去進行接口測試,測試是否對圖片驗證碼提取識別成功

  • 在代碼中進行如下編寫,對前面截取的註冊驗證碼進行識別,結果顯示識別成功;需要注意的是在網站提供的python示例代碼中的my_appId和my_appSecret的值需要從個人中心我的應用中去獲取的

  • 最後通過json.loads將字符串轉爲json對象並取值,從json中獲取圖片驗證碼的值

16.註冊輸入驗證碼流程整合

  • 現在我們將read_image_code中的代碼拷貝到start_browser中並將讀取到的圖片驗證碼的值自動填寫到驗證碼輸入框中

  • 運行代碼,成功打開網站讀取驗證碼正確,併成功在驗證碼框自動輸入驗證碼

17.註冊流程梳理及代碼封裝

  • 在項目目錄下創建register_code.py用於編寫註冊相關的核心代碼,完成用戶自動化註冊功能實現,說白點就是將之前的代碼整合一起進行封裝後一次性完成郵箱用戶名的隨機生成獲取驗證碼註冊即可,代碼如下

  • 測試自動化進行用戶註冊成功,爲了讓大家看到效果博主在測試時將driver.close已經註釋掉了

18.以配置文件形式實現定位設計思想

說明:當網站頁面的數據包括html代碼進行變更後,那麼我們封裝的代碼則需要進行對應的修改,這樣直接在代碼上進行修改肯定是很low的,那麼就需要創建一個項目的配置文件,將這樣定位元素放到配置文件中,在代碼只需要從配置文件中讀取數據即可,即使網站頁面變更我們只需要修改配置文件的數據即可

  • 在項目根目錄下創建config配置目錄,在該目錄下創建LocalElement.ini配置文件,在配置文件中將網站註冊頁面中input輸入框中中所有的元素數據進行如下的配置,以:分開前面的爲屬性後面爲屬性值

19.如何讀取配置文件low代碼

  • 首先需要安裝python的讀取ini文件的庫configparser

  • 然後在項目目錄下創建read_ini.py文件,在文件中對創建的LocalElement.ini文件中內容進行讀取

20.重構封裝讀取配置文件方法

  • 將read_ini中的代碼使用類進行封裝後,運行代碼同樣成功獲取出配置文件中user_email的數據

21.設計封裝定位元素類

  • 爲了降低代碼模塊的容錯率,需要在項目目錄下創建一個utils的python包,並且將read_ini.py文件拷貝到utils包下,然後再在項目目錄下創建一個find_element.py文件,用於操作對read_ini中獲取到的data數據進行分割分別獲取到元素類別屬性以及屬性值

22.如何將整個註冊流程腳本進行模塊化實戰

  • 在項目目錄下創建register_func.py腳本文件,在該文件中主要的邏輯爲整合register_code.py和read_ini.py以及find_element.py中的代碼完成整個註冊功能自動化腳本,詳細代碼如下,邏輯很簡單就是各種封裝各種調用最後整合即可

  • 測試自動化完成註冊功能成功,非常完美perfect

23.註冊失敗進行截圖處理

分析:在註冊頁面進行用戶註冊時,因郵箱地址和用戶名以及密碼是不可能報錯的,所導致註冊失敗的原因只有驗證碼錯誤

  • 根據驗證碼錯誤提示獲取頁面的元素信息

  • 緊接着在LocalElement.ini配置文件中添加驗證碼錯誤的配置數據

  • 然後在register_func中main方法中獲取驗證碼錯誤元素數據,當數據爲空時表示註冊成功,反正則失敗,爲了更好的演示註冊失敗,需要將代碼captcha_code對應的data數據傳遞爲xxxx數據,這樣做導致驗證碼肯定是錯誤的

  • 運行代碼後,在瀏覽器網站頁面中成功在驗證碼輸入框輸入指定的錯誤驗證碼,導致驗證碼錯誤

  • 查看代碼運行結果,成功提示出注冊失敗,說明邏輯正確

  • 最後查看註冊失敗保存到F:/selenium_image/code_error.png圖片

24.多瀏覽器跑case

  • 在啓動代碼中進行for循環根據遍歷生成的i的值來判斷driver的值,0代表使用Chrome,1代表Firefox,2代表Ie瀏覽器
if __name__ == '__main__':
    for i in range(3):
        RegisterFunc("http://www.5itest.cn/register", i).main()

  • 運行代碼後,均顯示註冊失敗,因爲驗證碼這一塊的值被我們寫死了

三丶項目實戰中PO模型的設計與封裝

說明:PO即Page Object設計模式,通俗解釋一下就是每個頁面當成一個對象,給這些頁面寫一個類,主要就是完成元素定位和業務操作;Page Object將測試對象及單個的測試步驟封裝在每個Page對象中,以page爲單位進行管理;優勢就是如果頁面元素髮生變化,你去維護頁面元素配置文件即可,測試類的代碼不需要更改

1.po模型設計思想

  • 前面完成了註冊功能的自動化測試,核心代碼爲register_func.py,該模塊可以完成自動化測試註冊功能,但是代碼的複用性很低,只適合註冊功能的自動化測試,要想在網站的其他頁面如登錄丶主頁以及搜索等等頁面進行測試的話是不可能的,所以需要在項目中使用po模型思想,對每個頁面都寫一個類進行單個測試,在項目進行如下的分層結構

2.po模型之如何設計操作層

  • 通過first_case.py模塊中註冊case得知需要去測試郵箱丶用戶名丶密碼丶驗證碼以及註冊功能是否錯誤或者成功,然後根據register_handle.py模塊來發送數據並進行處理頁面元素的數據,而在register_handle模塊於first_case模塊中則需要一個register_business.py模塊操作我們的register_handle模塊並將其進行組裝, 操作層結構如下

3.po模型設計之如何設計業務層

  • 通過把register_business模塊中的對應郵箱丶用戶名丶密碼丶驗證碼的判斷是否成功來判斷first_case模塊中的case是否成功,中間只是通過register_handle模塊中獲取註冊頁面的錯誤信息,在register_business通過調用獲取的錯誤信息來判斷返回True還是False,最後在first_case模塊中根據register_business模塊返回的Boolean值來進行下一步的處理操作,業務層結構如下

4.po模型設計之如何設計po及模塊串聯設計

思路:首先在項目根目錄下創建base包,然後這個包主要存放的是一些共同使用的模塊,將之前cdtaogang_selenium包下的find_element.py模塊拷貝到base包下,緊接着還需要創建一個page包,再在該包下創建一個register_page.py模塊,這個模塊的作用就是去調用find_element.py模塊的get_element方法通過傳遞的key的值到LocalElement.ini配置文件中去獲取註冊頁面元素數據,然後register_page模塊中將元素數據返回到register_handle模塊中向該元素髮送數據

  • 項目目錄體系如下

  • 核心代碼塊爲最開始的first_case——register_business——register_handle——register_page——find_element,說白了就是這幾個模塊之前的各種調用而已

5.po模型設計之如何把註冊頁面組裝成完整的自動化case

  • 首先需要在register_page模塊中完成獲取所有註冊頁面的元素,需要注意的是在register_handle模塊中的get_error_msg方法中需要獲取每個input框錯誤提示信息,所以需要在LocalElement.ini配置文件中添加錯誤信息配置

  • 緊接着在register_hanle模塊中也需要將其他輸入數據的方法進行補全,最後還需要獲取註冊頁面錯誤提示信息的值

6.po模型設計之註冊頁面常見業務case編寫

  • 首先在register_handle模塊中定義一個click_register方法,用戶註冊頁面註冊按鈕的點擊;然後再定義一個get_register_button_text獲取註冊頁面註冊按鈕的value值

  • 需要將整個po模型補全,首先在register_business模塊中對其餘輸入框的數據進行驗證,並定義一個register_success方法在這個方法中調用register_handle模塊中的get_register_button_text方法來判斷是否註冊成功,當頁面註冊成功後,則頁面就沒有註冊按鈕所在的元素了,即在find_element模塊中的get_element方法中會拋出異常返回None

  • 最後在first_case模塊中進行po模型分層case處理註冊頁面input輸入字段數據判斷,說白了就是前四個測試爲郵箱地址丶用戶名丶密碼丶驗證碼的分別輸入錯誤的數據進行錯誤測試,最後一個就是測試是否註冊成功;在測試case中當返回的email_error丶username_error丶password_error以及captcha_error的值爲爲True時表示通過調用的get_error_msg方法獲取註冊頁面的錯誤信息獲取不到則返回的是None,即在register_business模塊方法中表示錯誤信息驗證不成功返回True,那麼在first_case模塊中的測試case中則打印出"註冊成功了,此條case執行失敗",因爲當註冊頁面沒有錯誤提示信息元素值時,說明輸入的數據格式是正確的,反之則打印出"註冊失敗了,此條case執行成功"

7.po模型之流程梳理完成註冊頁面常見case調試

  • 在啓動文件first_case模塊中編寫運行代碼實例化FirstCase類,並調用測試方法,進行測試

  • 運行first_case模塊,查看測試效果

  • 根據測試效果,可以看到在執行到第二個case時,則沒有繼續往下執行,原因是當執行第一條case時也就是test_register_email_error方法,該方法是判斷頁面中是否存在郵箱地址錯誤的元素,當傳遞"xxx"郵箱地址時,肯定會出現錯誤提示,所以程序繼續往下執行沒有報錯,但是當執行第二條case時也就是test_register_username_error方法,在當前頁面上繼續輸入註冊數據,本來該方法測試的是錯誤的用戶名所以傳遞的是"lao",很明顯會出現用戶名的錯誤提示,重點但是頁面此時的註冊頁面的輸入框數據並沒有清空,所以導致註冊頁面上用戶名一欄的數據爲"laowanglao",即就是第一個case傳遞的name+第二個case傳遞的name,此時的用戶名長度大於4,所以此刻的註冊頁面用戶名錯誤提示信息的元素找不到,所以在調用get_error_msg方法裏代碼時傳遞的形參info的值爲email_error即調用get_user_email_error_element方法,此方法的核心就是調用get_element此時出現異常返回None,那麼回到get_error_msg方法中則調用text方法時報錯因爲None類型不存在任何方法,則在Pycharm控制檯提示以下錯誤,要解決此錯誤那麼則需要在每次點擊註冊後,需要將input框中的數據進行清空,但是這樣做需要重新去定位元素,還有一種方法則是使用unittest測試模塊運行代碼,這個在後面會使用到來解決此報錯

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章