selenium

寫在最前面:目前自動化測試並不屬於新鮮的事物,或者說自動化測試的各類方法論已經層出不窮,可是,可以在項目中鍥而不捨的實踐自動化測試的團隊,卻依舊不是很是多。有的團隊知道怎麼作,作的還不夠好;有的團隊還正在探索和摸索怎麼作,甚至還有一些多方面的技術上和非技術上的舊系統須要重構……css

本文將會從使用和實踐兩個視角,嘗試對基於Web UI自動化測試作細緻的分析和解讀,給各位去思考和實踐作一點引路,以便各團隊能找到更好的方式。html

1. 使用測試工具
《論語》有云:工欲善其事,必先利其器。在開始具體的自動化測試以前,咱們須要作好更多的準備,包括如下幾個方面:前端

認識自動化測試
準備自動化測試工具
使用有效的方式
針對具體的測試對象
接下來的第一部份內容,咱們將會從上述的幾個方面進行探討。node

1.1 自動化測試理論介紹
自動化測試的5Wpython

正如開篇所提到的,自動化測試再也不是一個陌生的話題,而是一個具體的存在。做爲測試實踐活動的一部分,咱們首先分析一下自動化測試的方方面面。mysql

WHAT, 什麼是自動化測試git

G.J.Myers在其經典的著做《軟件測試藝術》(The Art of Software Testing)一書中,給出了測試的定義:github

「程序測試是爲了發現錯誤而執行的過程。」web

這個概念產生於30年前,對軟件測試的認識還很是有侷限性,固然也是由於受瀑布開發模型的影響,認爲軟件測試是編程以後的一個階段。只有等待代碼開發出來之後,經過執行程序,像用戶那樣操做軟件去發現問題。sql

自動化測試:以人爲驅動的測試行爲轉化爲機器執行的一種過程

自動化測試,就是把手工進行的測試過程,轉變成機器自動執行的測試過程。該過程,依舊是爲了發現錯誤而執行。所以自動化測試的關鍵在於「自動化」三個字。自動化測試的內容,也就相應的轉變成如何「自動化」去實現本來手工進行的測試的過程。

全部的「自動化」,依靠的無疑都是程序。

經過程序,能夠把手工測試,轉變成自動化測試。

WHEN, 在何時開展自動化測試

自動化測試的開展,依賴於「程序」。那麼程序,其實就是由「源代碼」構建而來的。那麼原則上,只要能作出自動化測試所須要的「程序」的時候,變能夠進行自動化測試。但每每,並非全部的「時候」都是好的「時機」。從這個W開始,咱們將會加入對於成本的顧慮,也正是由於「成本」的存在,才使得下面的討論,變得有意義。

全部的開銷,都是有成本的。構建成「程序」的源代碼,也是由工程師寫出來的。那麼須要考慮這個過程當中的成本。基於這個考慮,在可以比較穩定的構建「程序」的時候,不須要花費太多開銷在「源代碼」的時候,就是開展自動化測試的好時機。這個開銷包括編寫和修改源代碼,而源代碼指的是構建出用來作自動化測試的程序的源代碼。

WHERE, 在什麼地方進行自動化測試

自動化測試的執行,依靠的是機器。那麼自動化測試必將在「機器」上進行。通常來講,這個機器包括桌面電腦和服務器。經過將寫好的源代碼部署在機器上,構建出用來作自動化測試的"程序",而且運行該程序,實現自動化測試。

WHICH, 對什麼目標進行自動化測試

自動化測試的目標,是被測試的軟件。拋開人工智能的成分,手工測試必將在「人工智能」足夠普及和足夠「智能」以前,替代一大部分不須要「人類智能」的手工測試;以及自動化測試會作一些手工測試沒法實施的,或者手工測試沒法覆蓋的測試。

不須要「人類智能」的普通手工測試
界面的普通操做
經過固定輸入和固定操做而進行的流程化測試
重複的普通測試
手工測試沒法實施或者覆蓋的
大量的數據的輸入
大量的步驟的操做
源代碼基本的測試
系統模塊間接口的調用測試
……
在這裏向你們推薦一個學習交流羣:672899761
HOW, 如何開展自動化測試

準備測試用例
找到合適的自動化測試工具
用準確的編程造成測試腳本
在測試腳本中對目標進行「檢查」,即作斷言
記錄測試日誌,生成測試結果
和全部的其餘測試同樣,自動化測試的流程也是由「用例」執行和「缺陷」驗證組成。差異是須要找到合適的「工具」來替代「人手」。不一樣目標的自動化測試有不一樣的測試工具,可是任何工具都無不例外的須要「編程」的過程,實現「源代碼」,也能夠稱之爲測試腳本。因而開展自動化測試的方式基本上以下:

自動化測試的典型金字塔原理

談到自動化測試,就不得不提的一我的和概念就是:Martin Fowler和他的金字塔原理。首先請看金字塔原理的圖示以下:

 

 

該圖說明了三個問題:

自動化測試包括三個方面:UI前端界面,Service服務契約和Unit底層單元
越是底層的測試,運行速度越快,時間開銷越少,金錢開銷越少
越是頂層的測試,運行速度越慢,時間開銷越多,金錢開銷越多
這是理想中的金字塔原理。

在實際的項目中,尤爲是結合國內的項目實踐,其實還隱藏了另外一個問題:越是頂層的測試,效果越明顯。有句話說「貴的東西,除了貴,其餘都是好的!」可以很清晰的闡述這個觀點。

金字塔原理在國內的適應性也有必定的問題

自動化測試的起步不是特別早
甚至軟件測試很長一段時間都在進行基於業務的手工測試,測試人員的代碼能力相對較弱
開發人員在代碼中不太習慣寫單元測試
近些年基於服務契約的API測試也在興起
相對來講,在基於UI前端界面的自動化測試反卻是開展和實施的不是特別多。儘管基於界面的測試帶來的效果仍是可以立竿見影的。對於產品的質量提高,仍是比較容易有保證。

自動化測試的適用範圍

自動化測試能夠涉及和試用的範圍主要在如下方面:

基於Web UI的瀏覽器應用的界面測試
基於WebService或者WebAPI的服務契約測試
基於WCF、.net remoting、Spring等框架的服務的集成測試
基於APP UI的移動應用界面測試
基於Java、C#等編程文件進行的單元測試
本文集中討論第一條:基於Web UI的瀏覽器應用的界面測試。界面的改動對於測試來講,具備較大的成本風險。主要考慮如下方面:

任務測試明確,不會頻繁變更
每日構建後的測試驗證
比較頻繁的迴歸測試
軟件系統界面穩定,變更少
須要在多平臺上運行的相同測試案例、組合遍歷型的測試、大量的重複任務
軟件維護週期長
項目進度壓力不太大
被測軟件系統開發比較規範,可以保證系統的可測試性
具有大量的自動化測試平臺
測試人員具有較強的編程能力
自動化測試的流程

自動化測試和普通的手工測試遵循的測試流程,與項目的具體實踐相關。通常來講,也是須要從測試計劃開始涉及自動化測試的。

測試計劃:劃定自動化測試的範圍包含哪些需求,涉及到哪些測試過程
測試策略:肯定自動化測試的工具、編程方案、代碼管理、測試重點
測試設計:使用測試設計方法對被測試的需求進行設計,得出測試的測試點、用例思惟導圖等
測試實施:根據測試設計進行用例編寫,而且將測試用例用編程的方式實現測試腳本
測試執行:執行測試用例,運行測試腳本,生成測試結果
1.2 自動化測試工具
基於Web UI的自動化測試工具主要有兩大類:付費的商業版工具和無償使用的開源版工具。典型的有兩種:

UFT,QTP被惠普收購之後的新名稱。
經過程序的錄製,能夠實現測試的編輯
錄製的測試腳本是 VBScript 語法
成熟版的商業付費工具
工具比較龐大,對具體的項目定製測試有難度
SELENIUM,本次選擇的開源工具
自己不是測試工具,只是模擬瀏覽器操做的工具
背後有 Google 維護源代碼
支持所有主流的瀏覽器
支持主流的編程語言,包括:Java、Python、C#、PHP、Ruby、JavaScript等
工具很小,能夠實現對測試項目的定製測試方案
基於標準的 WebDriver 語法規範
1.2.1 Selenium 基本介紹

Selenium`是開源的自動化測試工具,它主要是用於Web 應用程序的自動化測試,不僅侷限於此,同時支持全部基於web 的管理任務自動化。

Selenium官網的介紹

Selenium is a suite of tools to automate web browsers across many platforms.

runs in many browsers and operating systems
can be controlled by many programming languages and testing frameworks.
Selenium 官網:http://seleniumhq.org/
Selenium Github 主頁:https://github.com/SeleniumHQ/selenium
Selenium 是用於測試 Web 應用程序用戶界面 (UI) 的經常使用框架。它是一款用於運行端到端功能測試的超強工具。您可使用多個編程語言編寫測試,而且 Selenium 可以在一個或多個瀏覽器中執行這些測試。

Selenium 經歷了三個版本:Selenium 1,Selenium 2 和 Selenium 3。Selenium 也不是簡單一個工具,而是由幾個工具組成,每一個工具都有其特色和應用場景。

Selenium 誕生於 2004 年,當在 ThoughtWorks 工做的 Jason Huggins 在測試一個內部應用時。做爲一個聰明的傢伙,他意識到相對於每次改動都須要手工進行測試,他的時間應該用得更有價值。他開發了一個能夠驅動頁面進行交互的 Javascript 庫,能讓多瀏覽器自動返回測試結果。那個庫最終變成了 Selenium 的核心,它是 Selenium RC(遠程控制)和 Selenium IDE 全部功能的基礎。Selenium RC 是開拓性的,由於沒有其餘產品能讓你使用本身喜歡的語言來控制瀏覽器。這就是 Selenium 1。

然而,因爲它使用了基於 Javascript 的自動化引擎,而瀏覽器對 Javascript 又有不少安全限制,有些事情就難以實現。更糟糕的是,網站應用正變得愈來愈強大,它們使用了新瀏覽器提供的各類特性,都使得這些限制讓人痛苦不堪。

在 2006 年,一名 Google 的工程師, Simon Stewart 開始基於這個項目進行開發,這個項目被命名爲 WebDriver。此時,Google 早已經是 Selenium 的重度用戶,可是測試工程師們不得不繞過它的限制進行工具。Simon 須要一款能經過瀏覽器和操做系統的本地方法直接和瀏覽器進行通話的測試工具,來解決Javascript 環境沙箱的問題。WebDriver 項目的目標就是要解決 Selenium 的痛點。

到了 2008 年,Selenium 和 WebDriver 兩個項目合併。Selenium 有着豐富的社區和商業支持,但 WebDriver 顯然表明着將來的趨勢。二者的合併爲全部用戶提供了一組通用功能,而且借鑑了一些測試自動化領域最閃光的思想。這就是 Selenium 2。

2016 年,Selenium 3 誕生。移除了再也不使用的 Selenium 1 中的 Selenium RC,而且官方重寫了全部的瀏覽器驅動。

Selenium 工具集

Selenium IDE

Selenium IDE (集成開發環境) 是一個建立測試腳本的原型工具。它是一個 Firefox 插件,實現簡單的瀏覽器操做的錄製與回放功能,提供建立自動化測試的建議接口。Selenium IDE 有一個記錄功能,能記錄用戶的操做,而且能選擇多種語言把它們導出到一個可重用的腳本中用於後續執行。

Selenium RC

Selenium RC 是selenium 家族的核心工具,Selenium RC 支持多種不一樣的語言編寫自動化測試腳本,經過selenium RC 的服務器做爲代理服務器去訪問應用從而達到測試的目的。

selenium RC 使用分Client Libraries 和Selenium Server。

Client Libraries 庫主要主要用於編寫測試腳本,用來控制selenium Server 的庫。
Selenium Server 負責控制瀏覽器行爲,總的來講,Selenium Server 主要包括3 個部分:Launcher、Http Proxy、Core。
Selenium Grid

Selenium Grid 使得 Selenium RC 解決方案能提高針對大型的測試套件或者哪些須要運行在多環境的測試套件的處理能力。Selenium Grid 能讓你並行的運行你的測試,也就是說,不一樣的測試能夠同時跑在不一樣的遠程機器上。這樣作有兩個有事,首先,若是你有一個大型的測試套件,或者一個跑的很慢的測試套件,你可使用 Selenium Grid 將你的測試套件劃分紅幾份同時在幾個不一樣的機器上運行,這樣能顯著的提高它的性能。同時,若是你必須在多環境中運行你的測試套件,你能夠得到多個遠程機器的支持,它們將同時運行你的測試套件。在每種狀況下,Selenium Grid 都能經過並行處理顯著地縮短你的測試套件的處理時間。

Selenium WebDriver

WebDriver 是 Selenium 2 主推的工具,事實上WebDriver是Selenium RC的替代品,由於Selenium須要保留向下兼容性的緣由,在 Selenium 2 中, Selenium RC纔沒有被完全的拋棄,若是使用Selenium開發一個新的自動化測試項目,那麼咱們強烈推薦使用Selenium2 的 WebDriver進行編碼。另外, 在Selenium 3 中,Selenium RC 被移除了。

Python 語言的選擇,便捷

測試人員的編程能力廣泛不是很強,而Python做爲一種腳本語言,不只功能強大,並且語法優美,支持多種自動化測試工具,並且學習上手比較容易。
Python的社區發展比較好,有着很是多的文檔和支持庫,另外Python也能夠在Web開發、數據處理、科學計算等縱多領域有着很是好的應用前景。
對於有必定編程基礎的人員,使用Python做爲自動化測試的語言能夠很是順暢的轉換,幾乎沒有學習成本。同時Python是標準的面向對象的編程語言,對於C#、Java等面向對象的語言有着很是好的示例做用,經過Python的示例能夠很是輕鬆的舉一反三,使用其餘語言進行Selenium2.0的WebDriver的使用。
讀音:/'paɪθən/
Python的創始人爲Guido Van Rossum。1989年聖誕節期間,在阿姆斯特丹,Guido爲了打發聖誕節的無趣,決心開發一個新的腳本解釋程序,作爲ABC 語言的一種繼承。之因此選中Python(大蟒蛇的意思)做爲程序的名字,是由於他是一個叫Monty Python的喜劇團體的愛好者。
Python 語言除了在自動化測試領域有出色的表現外,在系統編程,網絡編程,web 開發,GUI開發,科學計算,遊戲開發等多個領域應用很是普遍,並且具備很是良好的社區支持。也就是說學習和掌握python 編程,實際上是爲你打開了一道更廣闊的大門。
使用的工具集

IDE: Jetbrains PyCharm
語言: Python
工具: Selenium WebDriver
源代碼管理: SVN/Git
1.2.2 JetBrains PyCharm 使用

JetBrains PyCharm 的介紹

PyCharm 是 JetBrains 公司針對Python推出的IDE(Integrated Development Environment,集成開發環境)。是目前最好的Python IDE之一。目前包含了兩個版本:

社區版,Community Edition
專業版,Professional Edition
付費
比社區版主要多了Web開發框架
咱們推薦使用免費的社區版本,進行Python腳本的編寫和自動化測試執行。

PyCharm能夠在官網下載,http://www.jetbrains.com

PyCharm 安裝後,若是也安裝過 Python 環境,能夠直接進行操做。不然請在 1.2.3 中安裝好 Python,再使用 PyCharm。

安裝按照默認的步驟安裝

使用方式

Create New Project:

建立新的項目,選擇項目建立的位置,選擇Python的解釋器

 

 

 

 

設置location,項目的路徑和名稱
名稱必須以英文字母開頭
名稱不能夠有空格
位置不能夠在 C:\Pytho34中,應該放到普通的目錄中
設置interpreter
一個電腦能夠裝多個 Python
這裏選擇一個你須要的 Pythpn
新建Python文件

 

 

 

 

在建立的文件中編寫第一個Python語句

print("hello Python!")


 

右鍵該文件,選擇Run hello,運行該語句,在下面的運行框中會顯示運行結果

C:\Python35\python.exe D:/Git/WeekendSelenium/untitled/hello.py
hello python!

Process finished with exit code 0
如圖

 

 

Open

打開已經存在的項目,好比別人發給你的項目,或者已經建立過的項目

 

 

 

 

安裝後進行設置以下:

設置行號的顯示

在PyCharm 裏,顯示行號有兩種辦法:

臨時設置(不推薦)。右鍵單擊行號處,選擇 Show Line Numbers。

 

 

可是這種方法,只對一個文件有效,而且,重啓PyCharm 後消失。

永久設置。File --> Settings -->Editor -->Appearance , 以後勾選Show Line Numbers。

 

 

設置字體

選擇 Settings | Editor | Colors & Fonts | Fonts

Save AS 主題

選擇 Source Code Pro(建議選擇,等寬字體)

SVN / Git 在工具中的集成

源代碼管理工具(VCS, version control system)

若是TortoiseSVN版本低於 1.8,須要先升級安裝1.8以上的版本

選擇SVN(git)做爲代碼的源代碼管理工具。集成在PyCharm中的步驟以下

代碼已經存在在SVN repo中:把代碼放到SVN在本地簽出(check out)的文件夾目錄中,例如 D:\SVN\XXProject\Trunck

 

 

代碼沒有建立:在本地的SVN項目文件夾中新建項目,用PyCharm打開,提交。

 

 

 

 

 

 

用PyCharm打開 剛剛部署的代碼

選擇PyCharm的 VCS|Enable VCS integration,選擇 Subversion(svn) 或者 Git

 

 

右鍵項目文件的根目錄,選擇 Subversion | add to VCS

 

 

右鍵項目文件的根目錄,或者選 VCS | Commit Directory...

 

 

 


 

天天打開代碼後,右鍵項目文件的根目錄,首先 Subversion | update project

若是有衝突,先本地手工保存你作的修改(備份你的文件到其餘地方,SVN目錄以外的地方,而後Revert)

1.2.3 Selenium 的環境搭建

在 Windows 搭建和部署 Selenium 工具

主要包括兩個步驟:

安裝 Python 語言

Python的官方網站:http://www.python.org

Python 目前並行了兩套版本,2.x 和 3.x。若是你以前沒有 Python 的使用經驗,建議使用 Python 3.x 版本。兩套版本互相不兼容,而且 Python 從 3.5(含)開始,再也不支持 Windows XP 系統,請注意。

選擇安裝目錄

3.4或者3.4如下的版本,都是 C:\python34
3.5以上的目錄,默認裝我的文件夾,建議用相似上面的目錄,好比C:\python35


 

勾選添加環境變量

勾選Add Python.exe to PATH

 

 

安裝過程當中不要關閉彈出來的命令行窗口

關於 Python 的安裝,也能夠選擇一些第三方的Python 安裝包,典型的有 Anaconda3,這樣的包有豐富的第三方庫,在使用 Python 的過程當中會更加方便。

Anaconda 的官網:https://www.continuum.io/anaconda-overview

安裝 Selenium 工具包

因爲 安裝好的 Python 默認有 pip Python 包管理工具,能夠經過 pip 很是方便的安裝 Selenium。

啓動命令行工具:Win+R | 輸入 cmd | 回車

輸入命令:

pip install selenium
該命令的執行須要有互聯網聯網環境。此外該命令有如下幾種選項可使用

安裝指定的版本,例如安裝指定的 Selenium 3.4.3

pip install selenium==3.4.3

安裝最新版的 Selenium

pip install -U selenium
# -U 也能夠用 --upgrade
pip install --upgrade selenium

卸載安裝當前的 Selenium

pip uninstall selenium
固然,若是您的機器處於非接入互聯網的環境,您能夠事先下載 Selenium 的 Python 安裝包,再進行手動安裝。

官方下載地址:https://pypi.python.org/pypi/selenium

上述地址會下載最新版的 Selenium,目前最早版的是 3.4.3,您也能夠根據如下路徑下載指定的 3.4.3

Selenium 3.4.3 下載地址:https://pypi.python.org/pypi/selenium/3.4.3#downloads

下載後,解壓該壓縮包

而後用命令行進入該壓縮包的根目錄,輸入命令進行安裝

python setup.py install

配置 瀏覽器 和 驅動

Selenium 2 能夠默認支持Firefox 46.0或者更低版本,對於其餘瀏覽器須要額外安裝驅動。

Selenium 3 對於全部的瀏覽器都須要安裝驅動,本文以 Chrome 和 Firefox、IE爲例設置瀏覽器和驅動。

ChromeDriver下載地址:http://chromedriver.storage.googleapis.com/index.html

ChromeDriver 與 Chrome 對應關係表:

ChromeDriver版本 支持的Chrome版本
v2.31 v58-60
v2.30 v58-60
v2.29 v56-58
v2.28 v55-57
v2.27 v54-56
v2.26 v53-55
v2.25 v53-55
v2.24 v52-54
v2.23 v51-53
v2.22 v49-52
v2.21 v46-50
v2.20 v43-48
GeckoDriver下載地址:https://github.com/mozilla/geckodriver/releases

GeckoDriver 與 Firefox 的對應關係表:

GeckoDriver版本 支持的Firefox版本
v0.18.0 v56
v0.17.0 v55
v0.16.0 v54,須要Selenium 3.4或者以上
v0.15.0 v53,須要Selenium 3.3或者以上
IEDriverServer下載地址:http://selenium-release.storage.googleapis.com/index.html

IEDriverServer 的版本須要與 Selenium 保持嚴格一致。

瀏覽器驅動的配置

首先,將下載好的對應版本的瀏覽器安裝。
其次,在 Python 的根目錄中,放入瀏覽器驅動。
最好再重啓電腦,通常狀況下不重啓也能夠的。

1.3 Selenium 的最簡腳本
經過上一節的環境安裝成功之後,咱們能夠進行第一個對Selenium 的使用,就是最簡腳本編寫。腳本以下:

# 聲明一個司機,司機是個Chrome類的對象
driver = webdriver.Chrome()

# 讓司機加載一個網頁
driver.get("http://demo.ranzhi.org")

# 給司機3秒鐘去打開
sleep(3)

# 開始登陸
# 1. 讓司機找用戶名的輸入框
we_account = driver.find_element_by_css_selector('#account')
we_account.clear()
we_account.send_keys("demo")

# 2. 讓司機找密碼的輸入框
we_password = driver.find_element_by_css_selector('#password')
we_password.clear()
we_password.send_keys("demo")

# 3. 讓司機找 登陸按鈕 並 單擊
driver.find_element_by_css_selector('#submit').click()
sleep(3)
實際上一段20行的代碼,也不能算太少了。可是這段代碼的使用,確實體現了 Selenium 的最簡單的使用。咱們在下面內容進行闡述。

關於面向對象編程

經過前面的介紹,咱們知道 Selenium 支持多種語言,而且推薦使用面向對象的方式進行編程。接下來咱們將着重介紹如何使用面向對象的方式進行編程。

咱們利用 Python 進行面向對象編程,須要首先了解一個概念:類

類是任何面向對象編程的語言的基本組成,描述了使用的基本方法。咱們可能在目前,還不是特別明白類的含義,可是咱們能夠經過類的使用,來進一步瞭解。

類的使用

類,經過實例化進行使用。好比有一個類: Driver,該類有一個方法: head(road)

那麼關於這個類的使用,只須要兩個步驟:

實例化該類:d = Driver()
調用類的方法:d.head("中山路")
瞭解上述例子和使用之後,咱們來看具體的 Selenium 的使用。

​這裏向你們推薦一個測試交流圈q裙:1007119548。

具體的對象的使用

在面向對象的理念看來,任何的編碼,都是由對象而來的,這裏也不例外。和以前介紹 WebDriver 時候的描述對應,咱們須要用到兩種主要的類,並將其實例化。

WebDriver 類:主要靠直接實例化該類爲對象,而後用其對象直接調用該類的方法和屬性
WebElement 類:主要經過 WebDriver 類實例化的對象,經過對頁面元素的查找,獲得 WebElement 類的對象,而後調用該類的方法和屬性。
上述代碼中,使用了一個 WebDriver 類 的對象,即第2行,聲明瞭該類的對象,並賦值給變量 driver,接着變量 driver 做爲 WebDriver 類的對象,使用了多個 WebDriver 類的方法。

注意:Chrome 是 WebDriver 的子類,是 WebDriver 類的一種

get(url): 第5行,打開網址
find_element_by_css_selector(selector): 第十二、1七、22行都使用了該方法,同時經過對該方法的調用,分別各產生了一個 WebElement類的對象,we_account,we_password和最後一個匿名的對象,並經過產生的三個對象,調用 WebElement 類的方法
clear():清理頁面元素中的文字
send_keys(text):給頁面元素中,輸入新的文字
click():鼠標左鍵點擊頁面元素
正是經過這樣的面向對象的方式,產生 Web司機(WebDriver類的對象),而且經過 Web司機不懈的努力,尋找到各類 Web元素(WebElement類的對象)進行操做,這樣便實現了 Selenium WebDriver 做爲一款出色的瀏覽器測試工具,進行瀏覽器UI界面的自動化測試的代碼編寫和用例執行。

1.4 Selenium WebDriver API 的使用
經過上述最簡腳本的使用,咱們能夠來進一步瞭解 Selenium 的使用。事實上,上一節用的,即是 Selenium 的 WebDriver API。API(Application Programming Interface,應用程序編程接口,即經過編程語言,操做 WebDriver 的方法集合)

Selenium WebDriver API 官方參考:http://seleniumhq.github.io/selenium/docs/api/py/

具體API文檔地址:https://seleniumhq.github.io/selenium/docs/api/py/api.html

API 使用: 用現成的類(大部分狀況)的方法進行編程
WebDriver
WebElement
API 文檔
編程使用說明
介紹了每一個方法的使用
方法的做用
方法的參數
方法的返回值
1.4.1 控制瀏覽器

瀏覽器的控制也是自動化測試的一個基本組成部分,咱們能夠將瀏覽器最大化,設置瀏覽器的高度和寬度以及對瀏覽器進行導航操做等。

# 瀏覽器打開網址
driver.get("https://www.baidu.com")

# 瀏覽器最大化
driver.maximize_window()

# 設置瀏覽器的高度爲800像素,寬度爲480像素
driver.set_window_size(480, 800)

# 瀏覽器後退
driver.back()

# 瀏覽器前進
driver.forward()

# 瀏覽器關閉
driver.close()

# 瀏覽器退出
driver.quit()
1.4.2 元素定位操做

WebDriver提供了一系列的定位符以便使用元素定位方法。常見的定位符有如下幾種:

id
name
class name
tag
link text
partial link text
xpath
css selector
那麼咱們如下的操做將會基於上述的定位符進行定位操做。

對於元素的定位,WebDriver API能夠經過定位簡單的元素和一組元素來操做。在這裏,咱們須要告訴Selenium如何去找元素,以致於他能夠充分的模擬用戶行爲,或者經過查看元素的屬性和狀態,以便咱們執行一系列的檢查。

在Selenium2中,WebDriver提供了多種多樣的find_element_by方法在一個網頁裏面查找元素。這些方法經過提供過濾標準來定位元素。固然WebDriver也提供了一樣多種多樣的find_elements_by的方式去定位多個元素。

儘管上述的方式,能夠進行元素定位,實際上咱們也是更多的用組合的方式進行元素定位。

方法Method 描述Description 參數Argument 示例Example
id 該方法經過ID的屬性值去定位查找單個元素 id: 須要被查找的元素的ID find_element_by_id('search')
name 該方法經過name的屬性值去定位查找單個元素 name: 須要被查找的元素的名稱 find_element_by_name('q')
class name 該方法經過class的名稱值去定位查找單個元素 class_name: 須要被查找的元素的類名 find_element_by_class_name('input-text')
tag_name 該方法經過tag的名稱值去定位查找單個元素 tag: 須要被查找的元素的標籤名稱 find_element_by_tag_name('input')
link_text 該方法經過連接文字去定位查找單個元素 link_text: 須要被查找的元素的連接文字 find_element_by_link_text('Log In')
partial_link_text 該方法經過部分連接文字去定位查找單個元素 link_text: 須要被查找的元素的部分連接文字 find_element_by_partial_link_text('Long')
xpath 該方法經過XPath的值去定位查找單個元素 xpath: 須要被查找的元素的xpath find_element_by_xpath('//*[@id="xx"]/a')
css_selector 該方法經過CSS選擇器去定位查找單個元素 css_selector: 須要被查找的元素的ID find_element_by_css_selector('#search')
接下來的列表將會詳細展現find_elements_by的方法集合。這些方法依據匹配的具體標準返回一系列的元素。

方法Method 描述Description 參數Argument 示例Example
id 該方法經過ID的屬性值去定位查找多個元素 id: 須要被查找的元素的ID find_elements_by_id('search')
name 該方法經過name的屬性值去定位查找多個元素 name: 須要被查找的元素的名稱 find_elements_by_name('q')
class_name 該方法經過class的名稱值去定位查找多個元素 class_name: 須要被查找的元素的類名 find_elements_by_class_name('input-text')
tag_name 該方法經過tag的名稱值去定位查找多個元素 tag: 須要被查找的元素的標籤名稱 find_elements_by_tag_name('input')
link_text 該方法經過連接文字去定位查找多個元素 link_text: 須要被查找的元素的連接文字 find_elements_by_link_text('Log In')
partial_link_text 該方法經過部分連接文字去定位查找多個元素 link_text: 須要被查找的元素的部分連接文字 find_elements_by_partial_link_text('Long')
xpath 該方法經過XPath的值去定位查找多個元素 xpath: 須要被查找的元素的xpath find_elements_by_xpath("//div[contains(@class,'list')]")
css_selector 該方法經過CSS選擇器去定位查找多個元素 css_selector: 須要被查找的元素的ID find_element_by_css_selector('.input_class')
依據ID查找

請查看以下HTML的代碼,以便實現經過ID的屬性值去定義一個查找文本框的查找:

<input id="search" type="text" name="q" value=""
class="input-text" maxlength="128" autocomplete="off"/>
根據上述代碼,這裏咱們使用find_element_by_id()的方法去查找搜索框而且檢查它的最大長度maxlength屬性。咱們經過傳遞ID的屬性值做爲參數去查找,參考以下的代碼示例:

def test_search_text_field_max_length(self):
# get the search textbox
search_field = self.driver.find_element_by_id("search")
# check maxlength attribute is set to 128
self.assertEqual("128", search_field.get_attribute("maxlength"))
若是使用find_elements_by_id()方法,將會返回全部的具備相同ID屬性值的一系列元素。

依據名稱name查找

這裏仍是根據上述ID查找的HTML代碼,使用find_element_by_name的方法進行查找。參考以下的代碼示例:

# get the search textbox
self.search_field = self.driver.find_element_by_name("q")
一樣,若是使用find_elements_by_name()方法,將會返回全部的具備相同name屬性值的一系列元素。

依據class name查找

除了上述的ID和name的方式查找,咱們還可使用class name的方式進行查找和定位。

事實上,經過ID,name或者類名class name查找元素是最提倡推薦的和最快的方式。固然Selenium2 WebDriver也提供了一些其餘的方式,在上述三類方式條件不足,查找無效的時候,能夠經過這些其餘方式來查找。這些方式將會在後續的內容中講述。

請查看以下的HTML代碼,經過改代碼進行練習和理解.

<button type="submit" title="Search" class="button">
<span><span>Search</span></span>
</button>
根據上述代碼,使用find_element_by_class_name()方法去定位元素。

def test_search_button_enabled(self):
# get Search button
search_button = self.driver.find_element_by_class_name("button")
# check Search button is enabled
self.assertTrue(search_button.is_enabled())
一樣的若是使用find_elements_by_class_name()方法去定位元素,將會返回全部的具備相同name屬性值的一系列元素。

依據標籤名tag name查找

利用標籤的方法相似於利用類名等方法進行查找。咱們能夠輕鬆的查找出一系列的具備相同標籤名的元素。例如咱們能夠經過查找表中的<tr>來獲取行數。

下面有一個HTML的示例,這裏在無序列表中使用了<img>標籤。

<ul class="promos">
<li>
<a href="http://demo.magentocommerce.com/home-decor.html">
<img src="/media/wysiwyg/homepage-three-column-promo-
01B.png" alt="Physical &amp; Virtual Gift Cards">
</a>
</li>
<li>
<a href="http://demo.magentocommerce.com/vip.html">
<img src="/media/wysiwyg/homepage-three-column-promo-
02.png" alt="Shop Private Sales - Members Only">
</a>
</li>
<li>
<a href="http://demo.magentocommerce.com/accessories/
bags-luggage.html">
<img src="/media/wysiwyg/homepage-three-columnpromo-
03.png" alt="Travel Gear for Every Occasion">
</a>
</li>
</ul>
這裏面咱們使用find_elements_by_tag_name()的方式去獲取所有的圖片,在此以前,咱們將會使用find_element_by_class_name()去獲取到指定的<ul>。

具體代碼以下:

def test_count_of_promo_banners_images(self):
# get promo banner list
banner_list = self.driver.find_element_by_class_name("promos")
# get images from the banner_list
banners = banner_list.find_elements_by_tag_name("img")
# check there are 20 tags displayed on the page
self.assertEqual(20, len(banners))
依據連接文字link查找

連接文字查找一般比較簡單。使用find_element_by_link_text請查看如下示例

<a href="#header-account" class="skip-link skip-account">
<span class="icon"></span>
<span class="label">ACCOUNT Description</span>
</a>
測試代碼以下:

def test_my_account_link_is_displayed(self):
# get the Account link
account_link =
self.driver.find_element_by_link_text("ACCOUNT Description")
# check My Account link is displayed/visible in
# the Home page footer
self.assertTrue(account_link.is_displayed())
依據部分連接文字partial text查找

這裏依舊使用上述的列子進行代碼編寫:

def test_account_links(self):
# get the all the links with Account text in it
account_links = self.driver.\
find_elements_by_partial_link_text("ACCOUNT")
# check Account and My Account link is
# displayed/visible in the Home page footer
self.assertTrue(2, len(account_links))
依據XPath進行查找

XPath是一種在XML文檔中搜索和定位節點node的一種查詢語言。全部的主流Web瀏覽器都支持XPath。Selenium2能夠用強大的XPath在頁面中查找元素。

經常使用的XPath的方法有starts-with(),contains()和ends-with()等

若想要了解更多關於XPath的內容,請查看http://www.w3schools.com/XPath/

以下有一段HTML代碼,其中裏面的<img>沒有使用ID,name或者類屬性,因此咱們沒法使用以前的方法。亞這裏咱們能夠經過<img>的alt屬性,定位到指定的tag。

<ul class="promos">
<li>
<a href="http://demo.magentocommerce.com/home-decor.html">
<img src="/media/wysiwyg/homepage-three-column-promo-
01B.png" alt="Physical &amp; Virtual Gift Cards">
</a>
</li>
<li>
<a href="http://demo.magentocommerce.com/vip.html">
<img src="/media/wysiwyg/homepage-three-column-promo-
02.png" alt="Shop Private Sales - Members Only">
</a>
</li>
<li>
<a href="http://demo.magentocommerce.com/accessories/
bags-luggage.html">
<img src="/media/wysiwyg/homepage-three-columnpromo-
03.png" alt="Travel Gear for Every Occasion">
</a>
</li>
</ul>
具體代碼以下:

def test_vip_promo(self):
# get vip promo image
vip_promo = self.driver.\
find_element_by_xpath("//img[@alt='Shop Private Sales - Members Only']")
# check vip promo logo is displayed on home page
self.assertTrue(vip_promo.is_displayed())
# click on vip promo images to open the page
vip_promo.click()
# check page title
self.assertEqual("VIP", self.driver.title)
固然,若是使用find_elements_by_xpath()的方法,將會返回全部匹配了XPath查詢的元素。

依據CSS選擇器進行查找

CSS是一種設計師用來描繪HTML文檔的視覺的層疊樣式表。通常來講CSS用來定位多種多樣的風格,同時能夠用來是一樣的標籤使用一樣的風格等。相似於XPath,Selenium2也可使用CSS選擇器來定位元素。

請查看以下的HTML文檔。

<div class="minicart-wrapper">
<p class="block-subtitle">Recently added item(s)
<a class="close skip-link-close" href="#" title="Close">×</a>
</p>
<p class="empty">You have no items in your shopping cart.
</p>
</div>
咱們來建立一個測試,驗證這些消息是否正確。

def test_shopping_cart_status(self):
# check content of My Shopping Cart block on Home page
# get the Shopping cart icon and click to open the
# Shopping Cart section
shopping_cart_icon = self.driver.\
find_element_by_css_selector("div.header-minicart
span.icon")
shopping_cart_icon.click()
# get the shopping cart status
shopping_cart_status = self.driver.\
find_element_by_css_selector("p.empty").text
self.assertEqual("You have no items in your shopping cart.",
shopping_cart_status)
# close the shopping cart section
close_button = self.driver.\
find_element_by_css_selector("div.minicart-wrapper
a.close")
close_button.click()
特殊 iframe 操做

iframe 元素會建立包含另一個文檔的內聯框架(即行內框架)。

iframe: 紫禁城

在一個<html>中,包含了另外一個<html>

示例

<html>
<head>
<title>iframe示例</title>
</head>
<body>
<h1>
這裏是H1,標記了標題
</h1>
<p>
這裏是段落,標記一個段落,屬於外層
</p>
<div>
<iframe id="iframe-1">
<html>
<body>
<p>
這裏是個段落,屬於內層,內聯框架中的
</p>
<div id="div-1">
<p class="hahahp">
這裏是div中的段落,須要被定位
</p>
</div>
</body>
</html>
</iframe>
</div>
</body>
</html>
須要定位上面示例中的<p>:這裏是div中的段落,須要被定位

以下是selenium WebDiriver的代碼

## 查找並定位 iframe
element_frame = driver.find_element_by_css_selector('#iframe-1')
## 切換到剛剛查找到的 iframe
driver.switch_to.frame(element_frame)
## 定位 <p>
driver.find_element_by_css_selector('#div-1 > p')
## TODO....
## 退出剛剛切換進去的 iframe
driver.switch_to.default_content()
特殊 Select 操做

<select> 是選擇列表

Select 是個selenium的類selenium.webdriver.support.select.Select

Select 類的路徑:

C:\Python35\Lib\site-packages\selenium\webdriver\support\select.py

<select id="brand">
<option value ="volvo">Volvo</option>
<option value ="saab">Saab</option>
<option value="opel">Opel</option>
<option value="audi">Audi</option>
</select>
示例,選擇 Audi

## 查找並定位到 select
element_select = driver.find_element_by_css_selector('#brand')
## 用Select類的構造方法,實例化一個對象 object_select
object_select = Select(element_select)
## 操做 object_select
object_select.select_by_index(3)
## 也能夠這樣
object_select.select_by_value('audi')
## 還能夠這樣
object_select.select_by_visible_text('Audi')
組合操做

自動化經驗的積累,須要100%按照手工的步驟進行操做。

好比步驟以下:

點擊一個 <a id="customer_chosen">
自動產生了一個 <ul id="customer_list">
點擊<ul>的第五個<li>
代碼示例

driver.find_element_by_css_selector('#customer_chosen').click()
sleep(1)
driver.find_element_by_css_selector('#customer_list > li:nth-child(5)')
1.4.3 鼠標事件操做

Web測試中,有關鼠標的操做,不僅是單擊,有時候還要作右擊、雙擊、拖動等操做。這些操做包含在ActionChains類中。

經常使用的鼠標方法:

context_click() # 右擊
double_click() # 雙擊
drag_and_drop() # 拖拽
move_to_element() # 鼠標停在一個元素上
click_and_hold() # 按下鼠標左鍵在一個元素上
例子:

# 方法模擬鼠標右鍵,參考代碼以下:
# 引入ActionChains 類
from selenium.webdriver.common.action_chains import ActionChains
...
# 定位到要右擊的元素
right =driver.find_element_by_xpath("xx")
# 對定位到的元素執行鼠標右鍵操做
ActionChains(driver).context_click(right).perform()
...
# 定位到要雙擊的元素
double = driver.find_element_by_xpath("xxx")
# 對定位到的元素執行鼠標雙擊操做
ActionChains(driver).double_click(double).perform()
1.4.4 鍵盤事件操做

鍵盤操做常常處理的以下:

代碼 描述
send_keys(Keys.BACKSPACE) 刪除鍵(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)
代碼以下

from selenium import webdriver

# 引入Keys 類包
from selenium.webdriver.common.keys import Keys
import time

driver = webdriver.Chrome()
driver.get("http://www.baidu.com")

# 輸入框輸入內容
driver.find_element_by_id("kw").send_keys("selenium")
time.sleep(3)

# 刪除多輸入的一個m
driver.find_element_by_id("kw").send_keys(Keys.BACK_SPACE)
time.sleep(3)

# 輸入空格鍵+「教程」
driver.find_element_by_id("kw").send_keys(Keys.SPACE)
driver.find_element_by_id("kw").send_keys("教程")
time.sleep(3)

# ctrl+a 全選輸入框內容
driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'a')
1.4.5 截圖操做

截圖的方法:save_screenshot(file)

1.5 unittest 單元測試框
在上一節,咱們對 Selenium WebDriver 的使用,僅僅停留在讓網頁自動的進行操做的階段,並無對任何一個步驟進行「檢查」。固然,這樣沒有「檢查」的操做,其實是沒有測試意義的。那麼第一項,咱們須要解決的即是「檢查」的問題。

所謂「檢查」,實際上就是斷言。對須要檢查的步驟操做,經過對預先設置的指望值,和執行結果的實際值之間的對比,獲得測試的結果。在這裏,咱們並不須要單獨的寫 if 語句進行各類斷定,而是可使用編程語言中對應的單元測試框架,便可解決好此類問題。

目前 Java 語言主流的單元測試框架有 JUnit 和 TestNG。Python 語言主流的單元測試框架有 unittest 。本小節的內容,主要介紹 unittest 的使用,探討單元測試框架如何幫助自動化測試。

接下來咱們將會使用 Python 語言的unittest框架展開「檢查」。unittest框架的本來的名字是PyUnit。是從JUnit 這樣一個被普遍使用的 經典的Java應用開發的單元測試框架創造而來。相似的框架還有NUnit(.Net開發的單元測試框架)等。咱們可使用unittest框架爲任意Python項目編寫可理解的單元測試集合。如今這個unittest已經做爲Python的標準庫模塊發佈。咱們安裝完Python之後,即可以直接使用unittest。

使用unittest須要如下簡單的三步:

引入unittest模組
繼承unittest.TestCase基類
測試方法以test開頭
unittest 並未使用 Java 語言常見的註解方式,依舊停留在 比較早期的 Java 版本中依靠方法名稱進行識別的方式。主要有如下兩個固定名字的方法:

setUp():在每一個測試方法運行前,執行。是測試前置條件。
tearDown():在每一個測試方法運行後執行,是測試清理操做。
具體的代碼以下:

## 引入unittest模組
import unittest

## 定義測試類,名字爲DemoTests
## 該類必須繼承unittest.TestCase基類
class DemoTests(unittest.TestCase):

## 使用'@'修飾符,註明該方法是類的方法
## setUpClass方法是在執行測試以前須要先調用的方法
## 是開始測試前的初始化工做
@classmethod
def setUpClass(cls):
print("call setUpClass()")

## 每個測試開始前的預置條件
def setUp(self):
print("call setUp()")

## 每個測試結束之後的清理工做
def tearDown(self):
print("call tearDown()")

## 測試一(務必以test開頭)
def test_01(self):
print("call test_01()")
pass

## 測試三(務必以test開頭)
def test_02(self):
print("call test_02()")
pass

## 測試三(務必以test開頭)
def test_03(self):
print("call test_03()")
pass

## tearDownClass方法是執行完全部測試後調用的方法
## 是測試結束後的清除工做
@classmethod
def tearDownClass(cls):
print("call tearDownClass()")

# 執行測試主函數
if __name__ == '__main__':
## 執行main全局方法,將會執行上述全部以test開頭的測試方法
unittest.main(verbosity=2)
須要注意步驟:

引入 unittest 模組
繼承 unittest.TestCase 類
作測試用例的方法,方法以 test_ 開頭
附加 setUp(), tearDown(), 在每一個 test_ 方法執行先後 進行執行
附加 setUpClass(), tearDownClass()
須要在 類實例化的對象,運行的開頭和結尾進行執行。
加了星號(*)的步驟,能夠不用。
上述代碼運行結果以下:

call setUpClass()
call setUp()
call test_01()
call tearDown()
call setUp()
call test_02()
call tearDown()
call setUp()
call test_06()
call tearDown()
call tearDownClass()
爲何選擇 unittest

清晰的單元測試框架,提供 TestCase, TestSuite, TextTestRunner 等基本類
unittest 是 原生 Python 的一部分
unittest 有第三方可用的 HTML 庫,能夠輕鬆的生成 測試報告
unittest 的斷言配置使用

unittest 的斷言,屬於 TestCase類,只要繼承了該類,都可以經過 self調用斷言

方法 Method 檢查條件
assertEqual(a, b [, msg]) a == b,msg可選,用來解釋失敗的緣由
assertNotEqual(a, b [, msg] a != b,msg可選,用來解釋失敗的緣由
assertTrue(x [, msg]) x 是真,msg可選,用來解釋失敗的緣由
assertFalse(x [, msg]) x 是假,msg可選,用來解釋失敗的緣由
assertIsNot(a, b [, msg]) a 不是 b,msg可選,用來解釋失敗的緣由
1.6 爲何須要封裝 Selenium
什麼是封裝

封裝是一個面向對象編程的概念,是面向對象編程的核心屬性,經過將代碼內部實現進行密封和包裝,從而簡化編程。對Selenium進行封裝的好處主要有以下三個方面:

使用成本低
不須要要求全部的測試工程師會熟練使用Selenium,而只須要會使用封裝之後的代碼
不須要對全部的測試工程師進行完整培訓。也避免工做交接的成本。
測試人員使用統一的代碼庫
維護成本低
經過封裝,在代碼發生大範圍變化和遷移的時候,不須要維護全部代碼,只須要變動封裝的部分便可
維護代碼不須要有大量的工程師,只須要有核心的工程師進行封裝的維護便可
代碼安全性
對做爲第三方的Selenium進行封裝,是代碼安全的基礎。
對於任何的代碼的安全隱患,必須由封裝來解決,使得風險可控。
使用者並不知道封裝內部的代碼結構。
1.7 封裝的概念與基本操做
關鍵方法的封裝思路

封裝的具體示例:

找到一個指定輸入框(selector),而且輸入指定的字符(text)

type(selector, text)

不用在業務邏輯中,使用屢次的 find_element_by_id(...))

def type(self, selector, text):
"""
Operation input box.
Usage:
driver.type("i,el","selenium")
"""
el = self._locate_element(selector)
el.clear()
el.send_keys(text)
找到一個能夠點擊的元素(selector),而且點擊(click)

click(selector)

def click(self, selector):
"""
It can click any text / image can be clicked
Connection, check box, radio buttons, and even drop-down box etc..

Usage:
driver.click("i,el")
"""
el = self._locate_element(selector)
el.click()
找到一個指定的frame,而且切換進去

switch_to_frame(selector)

def switch_to_frame(self, selector):
"""
Switch to the specified frame.
Usage:
driver.switch_to_frame("i,el")
"""
el = self._locate_element(selector)
self.base_driver.switch_to.frame(el)
找到一個指定的select,而且經過index進行選擇

select_by_index(selector, index)

def select_by_index(self, selector, index):
"""
It can click any text / image can be clicked
Connection, check box, radio buttons, and even drop-down box etc..

Usage:
driver.select_by_index("i,el")
"""
el = self._locate_element(selector)
Select(el).select_by_index(index)
以上的代碼是封裝了_locate_element()的幾種方法,在具體使用封裝過的代碼的時候,只須要簡單的調用便可。接下來的重點,是介紹 _locate_element(selector)的封裝方式。

查找元素:find_element_by_...)
支持各類的查找:8種方式都須要支持,必須經過 selector 顯示出分類
selector中須要包含一個特殊符號
實例化 封裝好的類的時候,須要約定好是什麼特殊符號
強制性用硬編碼 hard code來實例化,例如 , 或者 ? 或者 其餘很是用字符 =>
或者,構造方法中,傳遞 this.byChar
要把查找到元素的返回給調用的地方:必需要有返回值,類型是 WebElement
def _locate_element(self, selector):
"""
to locate element by selector
:arg
selector should be passed by an example with "i,xxx"
"x,//*[@id='langs']/button"
:returns
DOM element
"""
if self.by_char not in selector:
return self.base_driver.find_element_by_id(selector)

selector_by = selector.split(self.by_char)[0].strip()
selector_value = selector.split(self.by_char)[1].strip()
if selector_by == "i" or selector_by == 'id':
element = self.base_driver.find_element_by_id(selector_value)
elif selector_by == "n" or selector_by == 'name':
element = self.base_driver.find_element_by_name(selector_value)
elif selector_by == "c" or selector_by == 'class_name':
element = self.base_driver.find_element_by_class_name(selector_value)
elif selector_by == "l" or selector_by == 'link_text':
element = self.base_driver.find_element_by_link_text(selector_value)
elif selector_by == "p" or selector_by == 'partial_link_text':
element = self.base_driver.find_element_by_partial_link_text(selector_value)
elif selector_by == "t" or selector_by == 'tag_name':
element = self.base_driver.find_element_by_tag_name(selector_value)
elif selector_by == "x" or selector_by == 'xpath':
element = self.base_driver.find_element_by_xpath(selector_value)
elif selector_by == "s" or selector_by == 'css_selector':
element = self.base_driver.find_element_by_css_selector(selector_value)
else:
raise NameError("Please enter a valid type of targeting elements.")

return element

面向對象編程思想的運用

構造方法

普通方法
封裝後的方法如何被調用

使用上面的封裝類,就須要指定特定的 selector

類型 示例(分隔符以逗號,爲例) 描述
id "account" 或者 "i,account" 或者 "id,account" 分隔符左右兩側不能夠空格
xpath "x,//*[@id="s-menu-dashboard"]/button/i"  
css selector "s,#s-menu-dashboard > button > i"  
link text "l,退出"  
partial link text "p,退"  
name "n,name1"  
tag name "t,input"  
class name "c,dock-bottom  
具體調用示例

def login(self, account, password, keep):
"""
登陸系統
:param account:
:param password:
:param keep:
:return: 返回保持登陸複選框的 checked 值
"""
self.base_driver.type(self.LOGIN_ACCOUNT_SELECTOR, account)
self.base_driver.type(self.LOGIN_PASSWORD_SELECTOR, password)

current_checked = self.get_current_keep_value()
if keep:
if current_checked is None:
self.base_driver.click(self.LOGIN_KEEP_SELECTOR)
else:
if current_checked == "true":
self.base_driver.click(self.LOGIN_KEEP_SELECTOR)

actual_checked = self.get_current_keep_value()
self.base_driver.click(self.LOGIN_SUBMIT_SELECTOR)
sleep(2)
return actual_checked

1.8 Page-Object設計模式介紹
Page-Object設計模式的本質

Page Object設計模式是Selenium自動化測試項目的最佳設計模式之一,強調測試、邏輯、數據和驅動相互分離。

Page Object模式是Selenium中的一種測試設計模式,主要是將每個頁面設計爲一個Class,其中包含頁面中須要測試的元素(按鈕,輸入框,標題等),這樣在Selenium測試頁面中能夠經過調用頁面類來獲取頁面元素,這樣巧妙的避免了當頁面元素id或者位置變化時,須要改測試頁面代碼的狀況。當頁面元素id變化時,只須要更改測試頁Class中頁面的屬性便可。

它的好處以下:

集中管理元素對象,便於應對元素的變化
集中管理一個page內的公共方法,便於測試用例的編寫
後期維護方便,不須要重複的複製和修改代碼
具體的作法以下:

建立一個頁面的類
在類的構造方法中,傳遞 WebDriver 參數。
在測試用例的類中,實例化頁面的類,而且傳遞在測試用例中已經實例化的WebDriver對象。
在頁面的類中,編寫該頁面的全部操做的方法
在測試用例的類中,調用這些方法
Page 如何劃分

通常經過繼承的方式,進行按照實際Web頁面進行劃分

Page-Object 類如何實現

實現的示例

Page 基類

設計了一個基本的 Page類,以便全部的頁面進行繼承,該類標明瞭一個sub page類的基本功能和公共的功能。

全局變量: self.base_driver,讓全部的子類都使用的。

# 基類的變量,全部繼承的類,均可以使用
base_driver = None
構造方法:

傳遞 driver的構造方法

# 方法
def __init__(self, driver: BoxDriver):
"""
構造方法
:param driver: ":BoxDriver" 規定了 driver 參數類型
"""
self.base_driver = driver
私有的常量:存放元素的定位符

LOGIN_ACCOUNT_SELECTOR = "s, #account"
LOGIN_PASSWORD_SELECTOR = "s, #password"
LOGIN_KEEP_SELECTOR = "s, #keepLoginon"
LOGIN_SUBMIT_SELECTOR = "s, #submit"
LOGIN_LANGUAGE_BUTTON_SELECTOR = "s, #langs > button"
LOGIN_LANGUAGE_MENU_SELECTOR = "s, #langs > ul > li:nth-child(%d) > a"
LOGIN_FAIL_MESSAGE_SELECTOR = "s, body > div.bootbox.modal.fade.bootbox-alert.in > div > div > div.modal-body"
成員方法:

每一個子類都須要的系統功能:

open

def open(self, url):
"""
打開頁面
:param url:
:return:
"""
self.base_driver.navigate(url)
self.base_driver.maximize_window()
sleep(2)
全部子類(頁面)都具備的業務功能

select_app
logout
Sub Pages(s)子類

具體的頁面的類,定義了某個具體的頁面的功能

必須繼承基類

class MainPage(BasePage):
特定頁面的業務

使用基類的 self.base_driver 成員變量

Tests 類

這部分描述的是具體的測試用例。

聲明全局變量

base_driver = None
base_url = None
main_page = None
調用各類頁面(pages)

實例化Page

self.main_page = MainPage(self.base_driver)
使用page的對象,調用成員方法

self.main_page.open(self.base_url)
self.main_page.change_language(lang)

2. 構建測試方案
2.1 數據驅動在自動化測試中的應用
什麼是數據驅動

主要的數據驅動方式有兩種:

經過 文本文件或者 Excel 文件存儲數據,並經過程序讀取數據,遍歷全部的行
經過數據庫存儲數據,並經過程序和 SQL 腳本讀取數據,遍歷全部的行
經過 CSV 文件 或者 MySQL 數據庫,是主流的數據驅動方式。固然數據驅動也能夠結合單元測試框架的參數化測試進行編寫(此部分本文不作具體描述)。

不管使用了 哪種(CSV 或者 MySQL),讀取數據後都要進行遍歷操做。

使用 csv

import csv

csv_file = open("xxx.csv", "r", encoding="utf8")
csv_data = csv.reader(csv_file)
for row in csv_data:
# 進行測試
# 使用字典類型
data_to_test = {
"key1": row[0],
"key2": row[1]
}

csv_file.close()
使用 MySQL

import pymysql

connect = pymysql.connect(host="xx", port=3306, user="root", passwd="xxx", db="xx")
cur = connect.cursor()
cur.execute("SELECT...")
mysql_data = cur.fetchall()
for row in mysql_data:
# 進行測試
# 使用字典類型
data_to_test = {
"key1": row[0],
"key2": row[1]
}

cur.close()
connect.close()
須要掌握的知識點:

python的字典類型 dict 類型
python的讀寫文件
python的讀寫數據庫
for循環
注意資源的釋放
關閉數據庫遊標和鏈接
關閉文件
2.2 測試方案的編碼實現
main.py 測試入口
runner.py 測試運行器
cases 測試用例
pages 測試頁面
base 底層封裝與驅動
2.3 測試報告的生成
如何生成測試報告

測試報告的種類

HTML 測試報告的生成

HTML測試報告須要引入HTMLTestRunner

HTMLTestRunner是基於Python2.7的,咱們的課程講義基於Python3.x,那麼須要對這個文件作必定的修改。

測試的示例代碼以下

# 聲明一個測試套件
suite = unittest.TestSuite()
# 添加測試用例到測試套件
suite.addTest(RanzhiTests("test_ranzhi_login"))

# 建立一個新的測試結果文件
buf = open("./result.html", "wb")

# 聲明測試運行的對象
runner = HTMLTestRunner.HTMLTestRunner(stream=buf,
title="Ranzhi Test Result",
description="Test Case Run Result")
# 運行測試,而且將結果生成爲HTML
runner.run(suite)

# 關閉文件輸出buf.close()--------------------- 轉載自:https://blog.csdn.net/TestingGDR/article/details/81950593

相關文章
相關標籤/搜索