什麼是自動化測試?javascript
把人對軟件的測試行爲轉化爲由機器執行測試行爲的一種實踐, 自動化測試用例的維護成本高於其節省的測試成本時, 自動化測試就失去價值與意義,在這樣的項目中推動自動化測試就會得不償失.
自動化測試的優勢?css
能夠替代大量的手工機械重複性操做. 自動化測試能夠大幅提高迴歸測試的效率,很是適合敏捷開發過程; 能夠高效實現某些手工測試沒法完成或者代價巨大的測試類型. 能夠保證每次測試執行的操做以及驗證的一致性和可重複性,避免人爲的遺漏或疏忽。
自動化測試的缺點?html
並不能取代手工測試,只能替代手工測試中執行頻率高、機械化的重複步驟。不要奢望全部的測試都自動化,不然必定會得不償失。 自動測試遠比手動測試脆弱,沒法應對被測系統的變化,自動化測試用例的維護成本一直居高不下。對於執行過程當中出現的明顯錯誤和意外事件,自動化測試沒有任何處理能力。 自動化測試用例的開發工做量遠大於單次的手工測試. 手工測試發現的缺陷數量一般比自動化測試要更多,而且自動化測試僅僅能發現迴歸測試範圍的缺陷。 測試的效率很大程度上依賴自動化測試用例的設計以及實現質量,不穩定的自動化測試用例實現比沒有自動化更糟糕。 實行自動化測試的初期,用例開發效率一般都很低,大量初期開發的用例一般會在整個自動化測試體系成熟,和測試工程師全面掌握測試工具後,須要重構。 業務測試專家和自動化測試專家一般是兩批人,前者懂業務不懂自動化技術,後者懂自動化技術但不懂業務,只有兩者緊密合做,才能高效開展自動化測試。 自動化測試開發人員必須具有必定的編程能力,這對傳統的手工測試工程師會是一個挑戰。
什麼樣的項目適合自動化測試?前端
第一, 需求穩定,不會頻繁變動。需求不穩定,需求變動頻繁, 界面變化,或者是業務流程變化頻繁不適合. 第二, 研發和維護週期長,須要頻繁執行迴歸測試。對於短時間的一次性項目,我以爲你應該選擇手工探索式測試,以發現缺陷爲第一要務。而對於一些中長期項目,個人建議是:對比較穩定的軟件功能進行自動化測試,對變更較大或者需求暫時不明確的功能進行手工測試,最終目標是用 20% 的精力去覆蓋 80% 的迴歸測試。 第三, 須要在多種平臺上重複運行相同測試的場景. 第四, 測試項目經過手工測試沒法實現或手工成本過高。全部的性能和壓力測試,很難經過手工方式實現。 第五, 被測軟件的開發較爲規範,可以保證系統的可測試性。 第六, 測試人員已經具有必定的編程能力。
軟件開發各階段都有哪些自動化測試技術?java
單元測試、代碼級集成測試、Web Service 測試和 GUI 測試階段的自動化技術
單元測試的自動化技術包括:python
不只僅指測試用例執行的自動化,還包含如下五個方面: 用例框架代碼生成的自動化.部分測試輸入數據的自動化生成; 自動樁代碼的生成;被測代碼的自動化靜態分析(經常使用的代碼靜態分析工具備 Sonar 和 Coverity);測試覆蓋率的自動統計與分析。
代碼級集成測試的自動化技術:android
指將已經開發完成的軟件模塊放在一塊兒測試, 關注點更多的是軟件模塊之間的接口調用和數據傳遞。 代碼級集成測試與單元測試最大的區別只是,代碼級集成測試中被測函數內部調用的其餘函數必須是真實的,不容許使用樁代碼代替,而單元測試中容許使用樁代碼來模擬內部調用的其餘函數。 如今的開發理念追求的是系統複雜性的解耦,會去儘可能避免「大單體」應用,採用 Web Service 或者 RPC 調用的方式來協做完成各個軟件功能。因此如今的軟件企業,尤爲是互聯網企業,基本不會去作代碼級集成測試.
Web Service 測試的自動化技術:web
指 SOAP API 和 REST API 這兩類 API 測試,典型是採用 SoapUI 或 Postman 等相似的工具。但這類測試工具基本都是界面操做手動發起 Request 並驗證 Response,因此難以和 CI/CD 集成,因而就出現了 API 自動化測試框架。 **對於基於代碼的 API 測試用例,一般包含三大步驟:**準備 API 調用時須要的測試數據;準備 API 的調用參數併發起 API 的調用;驗證 API 調用的返回結果。 最流行的 API 自動測試框架是 REST Assured,它能夠方便地發起 Restful API 調用並驗證返回結果. Web Service 測試「自動化」的內涵不只僅包括 API 測試用例執行的自動化,還包括如下四個方面: 測試腳手架代碼的自動化生成;部分測試輸入數據的自動生成;Response 驗證的自動化;基於 SoapUI 或者 Postman 的自動化腳本生成。
GUI 測試的自動化技術chrome
核心思想是基於頁面元素識別技術,對頁面元素進行自動化操做,以模擬實際終端用戶的行爲並驗證軟件功能的正確性。 **GUI** **自動化測試主要分爲兩大方向,傳統 Web 瀏覽器和移動端原生應用(Native App)的 GUI 自動化。兩者採用的具體技術差異很大,用例設計的思路相似。Web端有selenium,** **Micro Focus** **的 UFT(前身是 HP 的 QTP).移動端有Appium等.** GUI 自動化測試的技術、原理和行業最佳實踐。 GUI 測試中兩個很是重要的概念:測試腳本和數據的解耦,以及頁面對象(Page Object)模型.
數據驅動(Data-driven)測試:shell
測試腳本只有一份,其中須要輸入數據的地方會用變量來代替,而後把測試輸入數據單獨放在一個文件中。這個存放測試輸入數據的文件,一般是表格的形式,也就是最多見的 CSV 文件。而後,在測試腳本中經過 data provider 去 CSV 文件中讀取一行數據,賦值給相應的變量,執行測試用例。接着再去 CSV 文件中讀取下一行數據,讀取完全部的數據後,測試結束。CSV 文件中有幾行數據,測試用例就會被執行幾回。 本質是實現了數據驅動的測試,讓操做相同可是數據不一樣的測試能夠經過同一套自動化測試腳原本實現,只是在每次測試執行時提供不一樣的測試輸入數據。
數據驅動的好處:
很好地解決了大量重複腳本的問題,實現了「測試腳本和數據的解耦」。數據驅動測試的數據文件中不只能夠包含測試輸入數據,還能夠包含測試驗證結果數據,甚至能夠包含測試邏輯分支的控制變量。數據驅動測試的思想不只適用於 GUI 測試,還能夠用於 API 測試、接口測試、單元測試等。
頁面對象模型(Page Object):
以頁面(Web Page 或者 Native App Page)爲單位來封裝頁面上的控件以及控件的部分操做。而測試用例,更確切地說是操做函數,基於頁面封裝對象來完成具體的界面操做,最典型的模式是「XXXPage.YYYComponent.ZZZOperation」。
如何把控操做函數的粒度?
操做函數的粒度是指,一個操做函數到底應該包含多少操做步驟纔是最合適的。以完成一個業務流程(business flow)爲主線,抽象出其中的「高內聚低耦合」的操做步驟集合,操做函數就由這些操做步驟集合構成。
如何銜接兩個操做函數之間的頁面?
若是連續的兩個操做函數之間沒法用頁面銜接,那就須要在兩個操做函數之間加入額外的頁面跳轉代碼,或者是在操做函數內部加入特定的頁面跳轉代碼。
GUI測試建立測試數據的方法:
從建立的技術手段上來說,建立測試數據的方法主要分爲三種:API 調用;數據庫操做;綜合運用 API 調用和數據庫操做。 從建立的時機來說,建立測試數據的方法主要分爲兩種:測試用例執行過程當中,實時建立測試數據,咱們一般稱這種方式爲 On-the-fly。測試用例執行前,事先建立好「開箱即用」的測試數據,一般稱這種方式爲 Out-of-box。 對於頁面對象自動生成,商用測試軟件已經實現。若是選擇開源測試框架,就須要本身實現這個功能了。 GUI 測試數據自動生成,主要是基於測試輸入數據的類型以及對應的自定義規則庫實現的,而且對於多個測試輸入數據,能夠基於笛卡爾積來自動組合出完整的測試用例集合。 對於無頭瀏覽器,你能夠把它簡單地想象成運行在內存中的瀏覽器,它擁有完整的瀏覽器內核。與普通瀏覽器最大的不一樣是,它在執行過程當中看不到運行的界面。目前,Headless Chrome 結合 Puppeteer 是最早進的無頭瀏覽器方案,若是感興趣,你能夠下載試用
GUI測試的穩定性:
要提升 GUI 測試穩定性,首先你須要知道究竟是什麼緣由引發的不穩定。你必須找出儘量多的不穩定因素,而後找到每一類不穩定因素對應的解決方案。
五種形成 GUI 測試不穩定的因素:非預計的彈出對話框;頁面控件屬性的細微變化;被測系統的 A/B 測試,隨機的頁面延遲形成控件識別失敗;測試數據問題。
非預計的彈出對話框能夠:
(1) 當自動化腳本發現控件沒法正常定位,或者沒法操做時,GUI 自動化框架自動**進入「異常場景恢復模式**. 在「異常場景恢復模式」下,GUI 自動化框架依次檢查各類可能出現的對話框,一旦確認了對話框的類型,當即執行預約義的操做(好比,單擊「肯定」按鈕,關閉這個對話框),接着重試剛纔失敗的步驟。而對於新類型的對話框,只能經過自動化的方式嘗試點擊上面的按鈕進行處理。每當發現一種潛在會彈出的對話框,咱們就把它的詳細信息(包括對象定位信息等)更新到「異常場景恢復」庫中,下次再遇到相同類型的對話框時,系統就可自動關閉。
頁面控件屬性的細微變化:
採用「組合屬性」定位控件會更精準**,並且成功率會更高,若是能在**此基礎上加入「模糊匹配」技術**,能夠進一步**提升控件的識別率**。可是,開源的 GUI 自動化測試框架,目前尚未現成的框架直接支持模糊匹配,一般須要你進行二次開發,實現思路是:實現本身的對象識別控制層,也就是在本來的對象識別基礎上額外封裝一層,在這個額外封裝的層中加上模糊匹配的實現邏輯。一般,不建議把模糊匹配邏輯以硬編碼的方式寫在代碼裏,而是引入規則引擎,將具體的規則經過配置文件的方式與代碼邏輯解耦。
被測系統的 A/B 測試:
在測試腳本內部對不一樣的被測版本作分支處理,腳本須要可以區分 A 和 B 兩個的不一樣版本,並作出相應的處理。
隨機的頁面延遲形成控件識別失敗:
加入重試(retry)機制。重試機制是指,當某一步 GUI 操做失敗時,框架會自動發起重試,重試**能夠是步驟級別的**,**也能夠是頁面級別的**,甚至是業務流程級別的。對於開源 GUI 測試框架,重試機制每每不是自帶的功能,須要本身二次開發來實現。須要特別注意的是,對於那些會修改一次性使用數據的場景,切忌不要盲目啓用頁面級別和**業務流程級別**的重試.
測試數據問題:略.
理想中的 GUI 測試報告
應該是由一系列按時間順序排列的屏幕截圖組成,而且這些截圖上能夠高亮顯示所操做的元素,同時按照執行順序配有相關操做步驟的詳細描述。
開源 GUI 測試框架的測試報告實現思路:
利用 Selenium WebDriver 的 screenshot 函數在一些特定的時機(好比,頁面發生跳轉時,在頁面上操做某個控件時,或者是測試失敗時,等等)完成界面截圖功能。具體到代碼實現,**一般有兩種方式:擴展 Selenium 本來的操做函數;在相關的 Hook 操做中調用 screenshot 函數。**
**第一,** **擴展 Selenium 本來的操做函數實現截圖以及高亮顯示操做元素的功能:** **本身實現的 click 函數被調用時:**首先,用 Javascript 代碼高亮顯示被操做的元素,高亮的實現方式就是利用 JavaScript 在對象的邊框上渲染一個 5-8 個像素的邊緣;而後,調用 screenshot 函數完成點擊前的截圖;最後,調用 Selenium 原生的 click 函數完成真正的點擊操做。那麼,之後凡是須要調用 click 函數時,都直接調用這個本身封裝的 click 函數,直接獲得高亮了被操做對象的界面截圖。 **第二,** **在相關的 Hook 操做中調用 screenshot 函數實現截圖以及高亮顯示操做元素的功能。** **第三,** **大型全球化電商網站的 GUI 自動化測試如何開展(若是你所在的企業或者項目正在大規模開展 GUI 測試,而且準備使用頁面對象模型以及業務流程封裝等最佳實踐的話):**
GUI 測試一般只覆蓋最核心且直接影響主營業務流程的 E2E 場景。
按照自底向上的順序分層次介紹 GUI 自動化的測試策略。 首先,要從前端組件的級別來保證質量,也就是須要對那些自定義開發的組件進行完整全面的測試。公共組件庫會被不少上層的前端模塊依賴,它的質量將直接影響這些上層模塊的質量,因此咱們每每會對這些公共組件進行嚴格的單元測試。最經常使用的方案是:基於 Jest 開展單元測試,並考量 JavaScript 的代碼覆蓋率指標。 完成單元測試後,每每還會基於被測控件構建專用的測試頁面,在頁面層面再次驗證控件相關的功能和狀態。這部分測試工做也須要採用自動化的形式實現,具體的作法是: 1. 先構建一個空頁面,並加入被測控件,由此能夠構建出一個包含被測控件的測試頁面,這個頁面每每被稱爲 Dummy Page; 2. 從黑盒的角度出發,在這個測試頁面上經過手工和自動化的方式操做被測控件,並驗證其功能的正確性。 對於自動化的部分,須要基於 GUI 自動化測試框架開發對應的測試用例。這些測試用例,每每採用和 GUI E2E 同樣的測試框架,也是從黑盒的角度來對被測控件作功能驗證。 **其次,每個前端模塊,都會構建本身的頁面對象庫,而且在此基礎上封裝開發本身的業務流程腳本。這些業務流程的腳本,能夠組裝成每一個前端模塊的測試用例。最後,組合各個前端模塊,並站在終端用戶的視角,以黑盒的方式使用網站的端到端(E2E)測試。**
monkey測試:
測試軟件的穩定性,健壯性的方法,通常能夠經過測試過程當中打印的日誌來發現問題。Monkey是經過命令行來對APP進行測試的工具,容許在模擬器裏或真機上。向系統發送僞隨機用戶時間流實現對應用程序進行壓力測試;
環境搭建:
win10需按照ADB工具, XA,而後再配置變量XB
實踐: 在手機開發者選項中,勾上USB調試。使用adb命令查看已鏈接設備:$adb devices
關閉adb的後臺進程: adb kill-server 讓手機脫離USB線的TCP鏈接方式: adb tcpip 開啓tcp鏈接方式鏈接手機: adb connect 收集日誌數據,用於後續的分析,好比耗電量: adb bugreport 發送壓測命令:對隨機應用執行100條monkey命令:adb shell monkey 1000 對特定應用進行monkey測試:adb shell monkey -P XXX.apk -v 測試次數 APP信息:獲取當前界面信息: adb shell dumpsys activity top 獲取任務列表: adb shell dumpsys activity activities 得到內存信息: adb shell dumpsys meminfo com.android.settings 獲取cpu信息: adb shell dumpsys cpuinfo 獲取特定包基本信息: adb shell dumpsys package xx 獲取當前activity: adb shell dumpsys activity top APP入口:adb logcat| findsdr -i displayed 或 appt dump badging xx.apk | grep lanunchable-activity 或 apkanalyzer 最新版本的sdk纔有 啓動應用: adb shell am start -n xxx -S 日誌查詢: adb logcat 當前應用查詢 adb logcat | findstr Displayed ADB SHELL:自己Linux的shell,能夠調用Android內置命令. adb shell dumpsys adb shell pm adb shell am adb shell ps adb shell monkey 清理應用緩存:adb shell pm clear 包名 顯示經常使用uiautomator命令: adb shell uiautomator 顯示經常使用輸入命令: adb shell input
Web測試框架,豐富的API,支持多種語言編寫測試腳本且可在多種瀏覽器執行測試腳本。
V1.0 和 V2.0 版本的技術方案是大相徑庭的,V1.0 的核心是 Selenium RC,而 V2.0 的核心是 WebDriver, V3.0 相比 V2.0 並無本質上的變化,主要是增長了對 MacOS 的 Safari 和 Windows 的 Edge 的支持,並完全刪除了對 Selenium RC 的支持。
server-client設計模式設計的。server端即瀏覽器。當咱們的腳本啓動瀏覽器後,等待client發送請求並作出相應;client端即測試代碼.
本地安裝Python,在官網下載,安裝時勾選path,安裝完成後,在cmd中輸入python,查看安裝成功. 安裝selenium,在cmd中輸入pip install selenium 安裝Chrome Webdriver:[官網](https://sites.google.com/a/chromium.org/chromedriver/downloads)
browser = webdriver.Chrome() browser = webdriver.Firefox() browser = webdriver.Safari() browser = webdriver.Ie()
from selenium import webdriver browser = webdriver.Chrome(executable_path="..\..\..\zc\chromedrive\chromedriver.exe") # executable_path來指定chromedirver路徑 browser.get('https://www.baidu.com') print(browser.title) browser.quit()
# 經過 id 定位 dr.find_element_by_id("kw") # 經過name定位: dr.find_element_by_name("wd") # 經過class name定位: dr.find_element_by_class_name("s_ipt") # 經過tag name定位: dr.find_element_by_tag_name("input") # 經過 xpath 定位的幾種寫法 dr.find_element_by_xpath("//*[@id='kw']") dr.find_element_by_xpath("//*[@name='wd']") dr.find_element_by_xpath("//input[@class='s_ipt']") dr.find_element_by_xpath("/html/body/form/span/input") dr.find_element_by_xpath("//span[@class='soutu-btn']/input") dr.find_element_by_xpath("//form[@id='form']/span/input") dr.find_element_by_xpath("//input[@id='kw' and @name='wd']") # 經過 css 定位的幾種寫法 dr.find_element_by_css_selector("#kw") dr.find_element_by_css_selector("[name=wd]") dr.find_element_by_css_selector(".s_ipt") dr.find_element_by_css_selector("html > body > form > span > input") dr.find_element_by_css_selector("span.soutu-btn> input#kw") dr.find_element_by_css_selector("form#form > span > input") # 經過 link_text 定位 dr.find_element_by_link_text("新聞") dr.find_element_by_link_text("hao123") dr.find_element_by_partial_link_text("新") dr.find_element_by_partial_link_text("hao") dr.find_element_by_partial_link_text("123") 定位一組元素:WebDriver還提供8種用於定位一組元素的方法。 find_elements_by_id() find_elements_by_name() find_elements_by_class_name() find_elements_by_tag_name() find_elements_by_link_text() find_elements_by_partial_link_text() find_elements_by_xpath() find_elements_by_css_selector()
set_window_size()方法來設置瀏覽器的大小 , maximize_window() 全屏顯示.如:browser.set_window_size(480,800) back()和 forward()方法來模擬後退和前進按鈕, refresh()方法模擬F5刷新頁面.
Clear()方法,清除文本. Send_keys(‘value’)方法,模擬鍵盤輸入. Click()方法,單擊元素. submit()方法用於提交表單. size: 返回元素的尺寸. text: 獲取元素的文本. get_attribute(name): 得到屬性值。is_displayed(): 設置該元素是否用戶可見。
在 WebDriver中鼠標操做的方法封裝在 ActionChains 類提供。經常使用方法以下: perform():執行全部 ActionChains 中存儲的行爲; move_to_element(): 鼠標懸停。 context_click(): 右擊; double_click(): 雙擊; drag_and_drop(): 拖動; 如: # 引入 ActionChains 類 from selenium.webdriver.common.action_chains import ActionChains # 定位到要懸停的元素 cc = browser.find_element_by_xpath('//*[@id="content"]/div/div[1]/div[2]/ul/li[4]/a') # 對定位到的元素執行鼠標懸停操做 ActionChains(browser).double_click(cc).perform()
Keys()類提供了鍵盤上幾乎全部按鍵的方法. # 引入 Keys 模塊 from selenium.webdriver.common.keys import Keys #經常使用鍵盤方法: send_keys(Keys.BACK_SPACE) 刪除鍵(BackSpace) send_keys(Keys.SPACE) 空格鍵(Space) send_keys(Keys.TAB) 製表鍵(Tab) send_keys(Keys.ESCAPE) 回退鍵(Esc) send_keys(Keys.ENTER) 回車鍵(Enter) send_keys(Keys.CONTROL,'a') 全選(Ctrl+A) send_keys(Keys.CONTROL,'c') 複製(Ctrl+C) send_keys(Keys.CONTROL,'x') 剪切(Ctrl+X) send_keys(Keys.CONTROL,'v') 粘貼(Ctrl+V) send_keys(Keys.F1) 鍵盤 F1 send_keys(Keys.F12) 鍵盤 F12
#測試時須要拿實際結果與預期結果進行比較,這個比較稱爲斷言 title:用於得到當前頁面的標題。 current_url:用戶得到當前頁面的URL。 text:獲取搜索條目的文本信息。 #WebDriver提供兩種類型的等待:顯式等待和隱式等待。 顯式等待:使WebdDriver等待某個條件成立時繼續執行,不然在達到最大時長時拋出超時異常(TimeoutException)。 隱式等待:WebDriver提供了implicitly_wait()方法來實現隱式等待,默認設置爲0。
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC import time base_url = 'http://www.baidu.com/' driver = webdriver.Chrome('../tools/chromedriver.exe') driver.get(base_url) # 1.顯示等待 # WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None) # driver :瀏覽器驅動。 # timeout :最長超時時間,默認以秒爲單位。 # poll_frequency :檢測的間隔(步長)時間,默認爲0.5S。 # ignored_exceptions :超時後的異常信息,默認狀況下拋NoSuchElementException異常 # until(method, message=‘’)-----調用該方法提供的驅動程序做爲一個參數,直到返回值爲True。 # until_not(method, message=‘’)---調用該方法提供的驅動程序做爲一個參數,直到返回值爲False。 # presence_of_element_located()方法判斷元素是否存在。 element = WebDriverWait(driver, 5, 0.5).until( EC.presence_of_element_located((By.ID, 'kw')) ) element.send_keys('要搜索的內容') time.sleep(3) driver.quit()
# 2. 隱式等待 from selenium.common.exceptions import NoSuchElementException from selenium import webdriver from time import ctime import time base_url2 = 'https://www.baidu.com/' browser = webdriver.Chrome('../tools/chromedriver.exe') # 設置隱式等待爲10s browser.implicitly_wait(10) browser.get(base_url2) try: print(ctime()) browser.find_element_by_id('kw').send_keys('se') time.sleep(3) except NoSuchElementException as e: print(e) finally: print(ctime()) browser.quit()
WebDriver只能在一個頁面上對元素識別與定位,對於frame/iframe表單內嵌頁面上的元素沒法直接定位。須要經過switch_to.frame()方法將當前定位的主體切換爲frame/iframe表單的內嵌頁面中。
如:browser.switch_to.frame(‘xx’) switch_to.frame() 默承認以直接取表單的id 或name屬性。若是iframe沒有可用的id和name屬性,則能夠經過下面的方式進行定位。 #先經過xpth定位到iframe xf = driver.find_element_by_xpath('//*[@id="x-URS-iframe"]') #再將定位對象傳給switch_to.frame()方法 driver.switch_to.frame(xf) …… driver.switch_to.parent_frame() 除此以外,在進入多級表單的狀況下,還能夠經過switch_to.default_content()跳回最外層的頁面。
WebDriver提供了switch_to.window()方法,能夠實如今不一樣的窗口之間切換。
current_window_handle:得到當前窗口句柄。
window_handles:返回全部窗口的句柄到當前會話。
switch_to.window():用於切換到相應的窗口,與上一節的switch_to.frame()相似,前者用於不一樣窗口的切換,後者用於不一樣表單之間的切換。
from selenium import webdriver import time base_url = 'https://www.baidu.com/' browser = webdriver.Chrome('../tools/chromedriver.exe') # 隱式等待10秒 browser.implicitly_wait(10) browser.get(base_url) # 得到搜索窗口的句柄 search_windows = browser.current_window_handle browser.find_element_by_link_text('登陸').click() browser.find_element_by_link_text('當即註冊').click() # 活得當前打開窗口的句柄 all_handles = browser.window_handles # 進入註冊窗口 for handle in all_handles: if handle != search_windows: browser.switch_to.window(handle) print('now register window!') browser.find_element_by_name('account').send_keys('username') browser.find_element_by_name('password').send_keys('password') time.sleep(2) browser.quit()
WebDriver中處理JavaScript所生成的alert、confirm以及prompt十分簡單.
具體作法是使用 switch_to.alert 方法定位到 alert/confirm/prompt,而後使用text/accept/dismiss/ send_keys等方法進行操做。
text:返回 alert/confirm/prompt 中的文字信息。 accept():接受現有警告框。
dismiss():解散現有警告框。 send_keys(keysToSend):發送文本至警告框。keysToSend:將文本發送至警告框。
from selenium import webdriver from selenium.webdriver.common.action_chains import ActionChains import time base_url = 'https://www.baidu.com/' driver = webdriver.Chrome('../tools/chromedriver.exe') driver.implicitly_wait(10) driver.get(base_url) # 鼠標懸停至 「設置」 連接 link = driver.find_element_by_link_text('設置') ActionChains(driver).move_to_element(link).perform() # 打開搜索設置 driver.find_element_by_link_text('搜索設置').click() time.sleep(3) # 點擊 「搜索設置」 driver.find_element_by_class_name('prefpanelgo').click() time.sleep(3) # 接受警告框prefpanelgo driver.switch_to.alert.accept() time.sleep(3) driver.quit()
WebDriver提供了Select類來處理下拉框, Select類用於定位select標籤。
select_by_value() 方法用於定位下接選項中的value值。
send_keys()方法來實現文件上傳
from selenium import webdriver from selenium.webdriver.support.select import Select from time import sleep base_url = 'https://www.baidu.com/' driver = webdriver.Chrome('../tools/chromedriver.exe') driver.implicitly_wait(10) driver.get(base_url) # 鼠標懸停至「設置」連接 driver.find_element_by_name('設置').click() sleep(2) # 打開 「搜索設置」 driver.find_element_by_name('搜索設置').click() sleep(2) # 搜索結果顯示條數 # Select類用於定位select標籤。 sel = driver.find_element_by_xpath("//select[@id='nr']") # select_by_value() 方法用於定位下接選項中的value值。 Select(sel).select_by_value('50') driver.quit()
經過input標籤實現的上傳功能,能夠將其看做是一個輸入框,即經過send_keys()指定本地文件路徑的方式實現文件上傳
from selenium import webdriver import os driver = webdriver.Chrome('../tools/chromedriver.exe') file_path = "file:///" + os.path.abspath('upfile.html') driver.get(file_path) # 定位上傳按鈕的位置 driver.find_element_by_name('file').send_keys(os.path.abspath('upfile.txt')) driver.quit()
get_cookies(): 得到全部cookie信息。 get_cookie(name): 返回字典的key爲「name」的cookie信息。 add_cookie(cookie_dict) : 添加cookie。「cookie_dict」指字典對象,必須有name 和value 值。 delete_cookie(name,optionsString):刪除cookie信息。「name」是要刪除的cookie的名稱,「optionsString」是該cookie的選項,目前支持的選項包括「路徑」,「域」。 delete_all_cookies(): 刪除全部cookie信息。 from selenium import webdriver from time import sleep base_url = 'https://www.baidu.com/' browser = webdriver.Chrome('../tools/chromedriver.exe') browser.get(base_url) # 1. 獲取 cookie 信息 cookies = browser.get_cookies() print(cookies) sleep(2) browser.quit() # 2. cookie 寫入 browser.add_cookie( { 'name': 'add-cookie', 'value': 'add-cookie-value' } ) # 遍歷cookies打印cookie信息 for cookie in browser.get_cookies(): print("%s ---> %s" % (cookie['name'], cookie['value'])) sleep(2) browser.quit()
WebDriver提供了execute_script()方法來執行JavaScript代碼。
WebDriver提供了截圖函數get_screenshot_as_file()來截取當前窗口。
rom selenium import webdriver from time import sleep base_url = 'https://www.baidu.com' browser = webdriver.Chrome('../tools/chromedriver.exe') browser.get(base_url) # window.scrollTo()方法用於設置瀏覽器窗口滾動條的水平和垂直位置。方法的第一個參數表示水平的左間距,第二個參數表示垂直的上邊距。 browser.set_window_size(500, 500) browser.find_element_by_id('kw').send_keys('百度') browser.find_element_by_id('su').click() sleep(2) # 經過javascript設置瀏覽器窗口的滾動條位置 js = "window.scrollTo(100, 450);" browser.execute_script(js) sleep(2) browser.quit()
webdriver 提供了截圖函數 get_screenshot_as_file() 來截取當前窗口
from selenium import webdriver from time import sleep base_url = 'http://www.baidu.com/' browser = webdriver.Chrome('../tools/chromedriver.exe') browser.get(base_url) browser.find_element_by_id('kw').send_keys('python selenium') browser.find_element_by_id('su').click() sleep(2) # 截取當前窗口並指定報錯截圖的位置 # browser.get_screenshot_as_file('ScreenShot/14_screenShot.jpg') browser.get_screenshot_as_file('ScreenShot/14_screenShot.png') browser.quit()
close() 關閉單個窗口 quit() 關閉全部窗口
Python自帶的單元測試框架,用於編寫和運行可重複的測試,主要用於白盒測試和迴歸測試
(1)讓測試具備持久性,測試與開發同步進行,測試代碼與開發代碼一併發佈; (2)能夠是測試代碼與產品代碼分離; (3)針對某一個類的測試代碼只需少許改動就能夠應用與另外一個類的測試; (4)使用斷言方法判斷指望值與實際值的差別,返回bool值; (5)測試驅動設備可使用共同的處理化變量或實例; (6)測試包結構便於組織集成運行。
unittest 要求單元測試類必須繼承 unittest.TestCase,該類中的測試方法須要知足以下要求:測試方法應該沒有返回值。測試方法不該該有任何參數。測試方法應以test 開頭。
#導入 unittest 這個模塊 import unittest #class 這一行是定義一個測試的類,並繼承 unittest.TestCase 這個類 class IntegerArithmeticTestCase(unittest.TestCase): # 接下來是定義了兩個測試case名稱: testAdd和testMultiply四、註釋裏面有句話很重要: #test method names begin 'test*'--翻譯:測試用例的名稱要以 test 開頭 def testAdd(self): # test method names begin with 'test' self.assertEqual((1 + 2), 3) self.assertEqual(0 + 1, 1) ##而後是斷言 assert,這裏的斷言方法是 assertEqual-判斷兩個是否相等,這個斷言能夠是一個也能夠是多個 def testMultiply(self): self.assertEqual((0 * 10), 0) self.assertEqual((5 * 8), 40) #if 下面的這個 unittest.main()是運行主函數,運行後會看到測試結果 if __name__ == '__main__': unittest.main()
一、setUp:在寫測試用例的時候,每次操做其實都是基於打開瀏覽器輸入對應網址這些操做,這個就是執行用例的前置條件。
二、tearDown:執行完用例後,爲了避免影響下一次用例的執行,通常有個數據還原的過程,這就是執行用例的後置條件。
三、不少小夥伴執行完用例,都不去作數據還原,以至於下一個用例執行失敗,這就是典型的本身給本身挖坑埋本身,本身坑本身,習慣很差。
四、前置和後置都是非必要的條件,若是沒有也能夠寫 pass
def setUP(self): pass def tearDown(self): pass
11 import unittest 12 13 #4.前置、後置 和運行測試 14 class Test(unittest.TestCase): 15 16 def setUp(self): 17 pass #若是沒有能夠不寫或者pass代替 18 19 def tearDown(self): 20 pass 21 22 def testSubtract(self): # test method names begin with 'test' 23 result = 6-5 #實際結果 24 hope = 1 #指望結果 25 self.assertEqual(result, hope) 26 27 def testDivide(self): 28 result = 7 / 2 # 實際結果 29 hope = 3.5 # 指望結果 30 self.assertEqual(result, hope) 31 32 if __name__ == '__main__': 33 unittest.main()
unittest的屬性:
unittest.TestCase**:TestCase類,全部測試用例類繼承的基本類。 class BaiduTest(unittest.TestCase): unittest.main(): 能夠方便的將一個單元測試模塊變爲可直接運行的測試腳本, main()方法使用TestLoader類來搜索全部包含在該模塊中以「test」命名開頭的測試方法,並自動執行他們。 執行方法的默認順序是:根據ASCII碼的順序加載測試用例,數字與字母的順序爲:0-9,A-Z,a-z。因此以A開頭的測試用例方法會優先執行,以a開頭會後執行。 unittest.TestSuite():unittest框架的TestSuite()類是用來建立測試套件的。 unittest.TextTextRunner(): unittest框架的TextTextRunner()類,經過該類下面的run()方法來運行suite所組裝的測試用例,入參爲suite測試套件。 unittest.defaultTestLoader(): defaultTestLoader()類,經過該類下面的discover()方法可自動更具測試目錄start\_dir匹配查找測試用例文件(test\*.py),並將查找到的測試用例組裝到測試套件,所以能夠直接經過run()方法執行discover。用法以下: discover=unittest.defaultTestLoader.discover(test_dir, pattern='test_*.py') unittest.skip():裝飾器,當運行用例時,有些用例可能不想執行等,可用裝飾器暫時屏蔽該條測試用例。一種常見的用法就是好比說想調試某一個測試用例,想先屏蔽其餘用例就能夠用裝飾器屏蔽。 @unittest.skip(reason): skip(reason)裝飾器:無條件跳過裝飾的測試,並說明跳過測試的緣由。 @unittest.skipIf(reason): skipIf(condition,reason)裝飾器:條件爲真時,跳過裝飾的測試,並說明跳過測試的緣由。 @unittest.skipUnless(reason): skipUnless(condition,reason)裝飾器:條件爲假時,跳過裝飾的測試,並說明跳過測試的緣由。 @unittest.expectedFailure(): expectedFailure()測試標記爲失敗。
TestCase類的屬性以下:
setUp(): 用於測試用例執行前的初始化工做。如測試用例中須要訪問數據庫,能夠在setUp中創建數據庫鏈接並進行初始化。如測試用例須要登陸web,能夠先實例化瀏覽器。 tearDown(): 用於測試用例執行以後的善後工做。如關閉數據庫鏈接。關閉瀏覽器。 assert*():一些斷言方法:在執行測試用例的過程當中,最終用例是否執行經過,是經過判斷測試獲得的實際結果和預期結果是否相等決定的。 ##!!注意,去掉\[ \] assertEqual(a,b,\[msg='測試失敗時打印的信息'\]):斷言a和b是否相等,相等則測試用例經過。 assertNotEqual(a,b,\[msg='測試失敗時打印的信息'\]):斷言a和b是否相等,不相等則測試用例經過。 assertTrue(x,\[msg='測試失敗時打印的信息'\]):斷言x是否True,是True則測試用例經過。 assertFalse(x,\[msg='測試失敗時打印的信息'\]):斷言x是否False,是False則測試用例經過。 assertIs(a,b,\[msg='測試失敗時打印的信息'\]):斷言a是不是b,是則測試用例經過。 assertNotIs(a,b,\[msg='測試失敗時打印的信息'\]):斷言a是不是b,不是則測試用例經過。 assertIsNone(x,\[msg='測試失敗時打印的信息'\]):斷言x是否None,是None則測試用例經過。 assertIsNotNone(x,\[msg='測試失敗時打印的信息'\]):斷言x是否None,不是None則測試用例經過。 assertIn(a,b,\[msg='測試失敗時打印的信息'\]):斷言a是否在b中,在b中則測試用例經過。 assertNotIn(a,b,\[msg='測試失敗時打印的信息'\]):斷言a是否在b中,不在b中則測試用例經過。 assertIsInstance(a,b,\[msg='測試失敗時打印的信息'\]):斷言a是是b的一個實例,是則測試用例經過。 assertNotIsInstance(a,b,\[msg='測試失敗時打印的信息'\]):斷言a是是b的一個實例,不是則測試用例經過。
TestSuite類的屬性以下:(組織用例時須要用到)
addTest(): addTest()方法是將測試用例添加到測試套件中,以下方,是將test_baidu模塊下的BaiduTest類下的test_baidu測試用例添加到測試套件。
suite = unittest.TestSuite() suite.addTest(test\_baidu.BaiduTest('test\_baidu'))
TextTextRunner的屬性以下:(組織用例時須要用到)
run(): run()方法是運行測試套件的測試用例,入參爲suite測試套件。
runner = unittest.TextTestRunner() runner.run(suite)
12 #4.執行順序和運行測試 13 import unittest 14 15 class TestLogin(unittest.TestCase): 16 17 def setUp(self): 18 pass 19 def test_login_blog(self): 20 """登陸博客園 21 22 :return: 23 """ 24 print("登陸博客園") 25 def test_add_essay(self): 26 """ 添加隨筆 27 28 :return: 29 """ 30 print("添加隨筆") 31 def test_release_essay(self): 32 """ 發佈隨筆 33 34 :return: 35 """ 36 print("發佈隨筆") 37 def test_quit_blog(self): 38 """退出博客園 39 40 :return: 41 """ 42 print("退出博客園") 43 44 def tearDown(self): 45 pass 46 if __name__ == '__main__': 47 # 啓動單元測試 48 # unittest.main() 49 50 # 獲取TestSuite的實例對象 51 suite = unittest.TestSuite() 52 53 # 將測試用例添加到測試容器中 54 suite.addTest(TestLogin('test_login_blog')) 55 suite.addTest(TestLogin('test_add_essay')) 56 suite.addTest(TestLogin('test_release_essay')) 57 suite.addTest(TestLogin('test_quit_blog')) 58 59 # 建立TextTestRunner類的實例對象 60 runner = unittest.TextTestRunner() 61 runner.run(suite) 62 #unittest.TextTestRunner(verbosity=3).run(suite)
11 import unittest 12 #4.執行順序和運行測試 13 import unittest 14 15 class TestLogin(unittest.TestCase): 16 17 def setUp(self): 18 pass 19 def test_1_login_blog(self): 20 """登陸博客園 21 22 :return: 23 """ 24 print("登陸博客園") 25 def test_2_add_essay(self): 26 """ 添加隨筆 27 28 :return: 29 """ 30 print("添加隨筆") 31 def test_3_release_essay(self): 32 """ 發佈隨筆 33 34 :return: 35 """ 36 print("發佈隨筆") 37 def test_4_quit_blog(self): 38 """退出博客園 39 40 :return: 41 """ 42 print("退出博客園") 43 44 def tearDown(self): 45 pass 46 if __name__ == '__main__': 47 # 啓動單元測試 48 unittest.main()
官方文檔
一個很是成熟的 Python 測試框架,能夠作到作個場景的測試工做,如:單元測試、接口測試、web測試等。 pytest兼容unittest測試用例,可是反過來unittest不兼容pytest, 是一個插件化平臺,豐富的插件擴展加強了它的功能,也能夠根據本身的須要定製化開發本身的插件,很是的靈活
import pytest class TestClass(object): def test_one(self): print("one case...\n") x = "test" assert 'e' in x def test_two(self): print("two case...\n") x = "hello" assert hasattr(x, 'check') if __name__ == "__main__": pytest.main()
由Qameta Software團隊開源的一款旨在於解決讓每一個人能更容易生成並更簡潔閱讀的測試報告框架。它支持大多數的測試框架,如:Pytest、TestNG等,簡單易用便於集成。
官網地址,注意必定別選最新的,還有項目名千萬別以pytest開頭
Allure要生效須要在測試文件和測試通配文件(conftest.py)中配置 allure。
pip3 install pytest pip3 install allure-pytest
前提配置Java1.8+的環境. 官網下載解壓,配置Path,變量爲安裝文件的allure.bat文件. 在cmd中輸入allure,查看是否安裝成功.
import pytest import allure # allure.feature 定義功能 @allure.feature("報告購物車") class TestAllure(object): # 定義用戶場景 @allure.story("加入購物車") def test_add_goods_cart(self): # 調用步驟函數 login("crisimple", "123456") # 將測試用例分紅幾個步驟,將測試步驟打印到測試報告中,步驟二 with allure.step("瀏覽商品"): # allure.attach--打印一些附加信息 allure.attach("商品1", "C") allure.attach("商品2", "C") # 步驟三 with allure.step("加入商品"): allure.attach("商品1", 2) allure.attach("商品2", 3) # 步驟四 with allure.step("校驗商品"): allure.attach("商品1加入成功", "共2個") allure.attach("商品2加入失敗", "共0個") @allure.story("繼續購物") def test_continue_shopping_cart(self): login("crisimple", "123456") allure.attach("商品3", 4) print("繼續購物成功") @allure.story("減小商品失敗") def test_edit_shopping_cart(self): login("crisimple", "123") assert 0 @pytest.mark.skip(reason="刪除購物車不執行") @allure.story("刪除購物車") def test_delete_shopping_cart(self): login("crisimple", "123") print() # 將函數做爲一個步驟,調用此函數時,報告中輸出一個步驟,步驟名稱一般時函數名,這樣的函數一般稱爲步驟函數 @allure.step("用戶登陸") def login(user, passwd): if user == "crisimple" and passwd == "123456": print(user, passwd) print("登陸成功") else: print(user, passwd) print("登陸失敗,請從新嘗試")
# 在文件地址打開cmd,假設文件名爲test_demo.py,生成json格式運行結果 pytest --alluredir=report test_demo.py $命令中的 --alluredir=report 指明瞭生成的json結果文件存放的目錄爲當前目錄下的report文件夾 # 使用`allure`生成最終的測試報告 allure generate report #實際內容須要 `allure` 進行渲染後才能看到 allure open allure-report
Feature: 標註主要功能模塊 Story: 標註Features功能模塊下的分支功能 Severity: 標註測試用例的重要級別 Step: 標註測試用例的重要步驟 Issue和TestCase: 標註Issue、Case,可加入URL
(1) 掘金博主
(2) unittest官方文檔連接:中文文檔,英文文檔
(3) 實戰接口項目
(4) 掘金博客_自動化測試**