selenium自動(dòng)化測(cè)試基礎(chǔ)
- 1. 使用測(cè)試工具
- 2. 構(gòu)建測(cè)試方案
原文閱讀對(duì)象是針對(duì)測(cè)試人員,測(cè)試人員普遍開(kāi)發(fā)能力偏弱,所以講的比較瑣碎,這里做了一定的刪減和改寫,主要針對(duì)測(cè)試主管或有一定經(jīng)驗(yàn)的開(kāi)發(fā)人員或負(fù)責(zé)人,快速了解及考慮使用selenium自動(dòng)化測(cè)試方案。
自動(dòng)化測(cè)試并不屬于新鮮的事物,或者說(shuō)自動(dòng)化測(cè)試的各種方法論已經(jīng)層出不窮,但是,能夠在項(xiàng)目中持之以恒的實(shí)踐自動(dòng)化測(cè)試的團(tuán)隊(duì),卻依舊不是非常多。有的團(tuán)隊(duì)知道怎么做,做的還不夠好;有的團(tuán)隊(duì)還正在探索和摸索怎么做,甚至還有一些多方面的技術(shù)上和非技術(shù)上的舊系統(tǒng)需要重構(gòu)……
本文從
使用和實(shí)踐兩個(gè)視角,嘗試對(duì)基于Web UI自動(dòng)化測(cè)試做細(xì)致的分析和解讀,給各位去思考和實(shí)踐做一點(diǎn)引路,以便各團(tuán)隊(duì)能找到更好的方式。
1. 使用測(cè)試工具
在開(kāi)始具體的自動(dòng)化測(cè)試之前,我們需要做好更多的準(zhǔn)備,包括以下幾個(gè)方面:
- 認(rèn)識(shí)自動(dòng)化測(cè)試
- 準(zhǔn)備自動(dòng)化測(cè)試工具
- 使用有效的方式
- 針對(duì)具體的測(cè)試對(duì)象
1.1 自動(dòng)化測(cè)試?yán)碚摻榻B
自動(dòng)化測(cè)試不再是一個(gè)陌生的話題,作為測(cè)試實(shí)踐活動(dòng)的一部分,我們首先分析一下自動(dòng)化測(cè)試的方方面面。
自動(dòng)化測(cè)試的4W1H
-
WHAT- 什么是自動(dòng)化測(cè)試《軟件測(cè)試藝術(shù)》一書中,給出了測(cè)試的定義:
“程序測(cè)試是為了發(fā)現(xiàn)錯(cuò)誤而執(zhí)行的過(guò)程?!?/p>
自動(dòng)化測(cè)試:以人為驅(qū)動(dòng)的測(cè)試行為轉(zhuǎn)化為機(jī)器執(zhí)行的一種過(guò)程
自動(dòng)化測(cè)試,就是把手工進(jìn)行的測(cè)試過(guò)程,轉(zhuǎn)變成機(jī)器自動(dòng)執(zhí)行的測(cè)試過(guò)程。該過(guò)程,依舊是為了發(fā)現(xiàn)錯(cuò)誤而執(zhí)行。因此自動(dòng)化測(cè)試的關(guān)鍵在于“自動(dòng)化”三個(gè)字。自動(dòng)化測(cè)試的內(nèi)容,也就相應(yīng)的轉(zhuǎn)變成如何“自動(dòng)化”去實(shí)現(xiàn)原本手工進(jìn)行的測(cè)試的過(guò)程。
通過(guò)程序,可以把手工測(cè)試,轉(zhuǎn)變成自動(dòng)化測(cè)試。
-
WHEN- 在什么時(shí)候開(kāi)展自動(dòng)化測(cè)試自動(dòng)化測(cè)試的開(kāi)展,依賴于“程序”。那么程序,其實(shí)就是由“源代碼”構(gòu)建而來(lái)的。那么原則上,只要能做出自動(dòng)化測(cè)試所需要的“程序”的時(shí)候,就可以進(jìn)行自動(dòng)化測(cè)試。但往往,并不是所有的“時(shí)候”都是好的“時(shí)機(jī)”。從這個(gè)
W開(kāi)始,我們將會(huì)加入對(duì)于成本的顧慮,也正是因?yàn)椤俺杀尽钡拇嬖?,才使得下面的討論,變得有意義。所有的開(kāi)銷,都是有成本的。構(gòu)建成“程序”的源代碼,也是由工程師寫出來(lái)的。那么需要考慮這個(gè)過(guò)程中的成本?;谶@個(gè)考慮,在能夠比較穩(wěn)定的構(gòu)建“程序”的時(shí)候,不需要花費(fèi)太多開(kāi)銷在“源代碼”的時(shí)候,就是開(kāi)展自動(dòng)化測(cè)試的好時(shí)機(jī)。這個(gè)開(kāi)銷包括
編寫和修改源代碼,而源代碼指的是構(gòu)建出用來(lái)做自動(dòng)化測(cè)試的程序的源代碼。 -
WHERE- 在什么地方進(jìn)行自動(dòng)化測(cè)試自動(dòng)化測(cè)試的執(zhí)行,依靠的是機(jī)器。那么自動(dòng)化測(cè)試必將在“機(jī)器”上進(jìn)行。一般來(lái)說(shuō),這個(gè)機(jī)器包括桌面電腦和服務(wù)器。通過(guò)將寫好的
源代碼部署在機(jī)器上,構(gòu)建出用來(lái)做自動(dòng)化測(cè)試的"程序",并且運(yùn)行該程序,實(shí)現(xiàn)自動(dòng)化測(cè)試。 -
WHICH- 對(duì)什么目標(biāo)進(jìn)行自動(dòng)化測(cè)試自動(dòng)化測(cè)試的目標(biāo),是被測(cè)試的軟件。拋開(kāi)人工智能的成分,手工測(cè)試必將在“人工智能”足夠普及和足夠“智能”之前,替代一大部分不需要“人類智能”的手工測(cè)試;以及自動(dòng)化測(cè)試會(huì)做一些手工測(cè)試無(wú)法實(shí)施的,或者手工測(cè)試無(wú)法覆蓋的測(cè)試。
- 不需要“人類智能”的普通手工測(cè)試
- 界面的普通操作
- 通過(guò)固定輸入和固定操作而進(jìn)行的流程化測(cè)試
- 重復(fù)的普通測(cè)試
- 手工測(cè)試無(wú)法實(shí)施或者覆蓋的
- 大量的數(shù)據(jù)的輸入
- 大量的步驟的操作
- 源代碼基本的測(cè)試
- 系統(tǒng)模塊間接口的調(diào)用測(cè)試
- ……
-
HOW- 如何開(kāi)展自動(dòng)化測(cè)試- 準(zhǔn)備測(cè)試用例
- 找到合適的自動(dòng)化測(cè)試工具
- 用準(zhǔn)確的編程形成測(cè)試腳本
- 在測(cè)試腳本中對(duì)目標(biāo)進(jìn)行“檢查”,即做斷言
- 記錄測(cè)試日志,生成測(cè)試結(jié)果
和所有的其他測(cè)試一樣,自動(dòng)化測(cè)試的流程也是由“用例”執(zhí)行和“缺陷”驗(yàn)證組成。差別是需要找到合適的“工具”來(lái)替代“人手”。不同目標(biāo)的自動(dòng)化測(cè)試有不同的測(cè)試工具,但是任何工具都無(wú)不例外的需要“編程”的過(guò)程,實(shí)現(xiàn)“源代碼”,也可以稱之為測(cè)試腳本。
于是開(kāi)展自動(dòng)化測(cè)試的方式基本上如下:
自動(dòng)化測(cè)試的典型金字塔原理
談到自動(dòng)化測(cè)試,就不得不提的一個(gè)人和概念就是:Martin Fowler和他的金字塔原理。首先請(qǐng)看金字塔原理的圖示如下:

該圖說(shuō)明了三個(gè)問(wèn)題:
- 自動(dòng)化測(cè)試包括三個(gè)方面:UI前端界面,Service服務(wù)契約和Unit底層單元
- 越是底層的測(cè)試,運(yùn)行速度越快,時(shí)間開(kāi)銷越少,金錢開(kāi)銷越少
- 越是頂層的測(cè)試,運(yùn)行速度越慢,時(shí)間開(kāi)銷越多,金錢開(kāi)銷越多
這是理想中的金字塔原理。
在實(shí)際的項(xiàng)目中,尤其是結(jié)合國(guó)內(nèi)的項(xiàng)目實(shí)踐,其實(shí)還隱藏了另一個(gè)問(wèn)題:越是頂層的測(cè)試,效果越明顯。有句話說(shuō)“貴的東西,除了貴,其他都是好的!”能夠很清晰的闡述這個(gè)觀點(diǎn)。
金字塔原理在國(guó)內(nèi)的適應(yīng)性也有一定的問(wèn)題
- 自動(dòng)化測(cè)試的起步不是特別早
- 甚至軟件測(cè)試很長(zhǎng)一段時(shí)間都在進(jìn)行基于業(yè)務(wù)的手工測(cè)試,測(cè)試人員的代碼能力相對(duì)較弱
- 開(kāi)發(fā)人員在代碼中不太習(xí)慣寫單元測(cè)試
- 近些年基于服務(wù)契約的API測(cè)試也在興起
相對(duì)來(lái)說(shuō),在基于UI前端界面的自動(dòng)化測(cè)試反倒是開(kāi)展和實(shí)施的不是特別多。盡管基于界面的測(cè)試帶來(lái)的效果還是能夠立竿見(jiàn)影的。對(duì)于產(chǎn)品的質(zhì)量提升,還是比較容易有保證。
自動(dòng)化測(cè)試的適用范圍
自動(dòng)化測(cè)試可以涉及和試用的范圍主要在以下方面:
- 基于
Web UI的瀏覽器應(yīng)用的界面測(cè)試 - 基于
WebService或者WebAPI的服務(wù)契約測(cè)試 - 基于
WCF、.net remoting、Spring等框架的服務(wù)的集成測(cè)試 - 基于
APP UI的移動(dòng)應(yīng)用界面測(cè)試 - 基于
Java、C#等編程文件進(jìn)行的單元測(cè)試
本文集中討論第一條:基于Web UI的瀏覽器應(yīng)用的界面測(cè)試。界面的改動(dòng)對(duì)于測(cè)試來(lái)說(shuō),具有較大的成本風(fēng)險(xiǎn)。主要考慮以下方面:
- 任務(wù)測(cè)試明確,不會(huì)頻繁變動(dòng)
- 每日構(gòu)建后的測(cè)試驗(yàn)證
- 比較頻繁的回歸測(cè)試
- 軟件系統(tǒng)界面穩(wěn)定,變動(dòng)少
- 需要在多平臺(tái)上運(yùn)行的相同測(cè)試案例、組合遍歷型的測(cè)試、大量的重復(fù)任務(wù)
- 軟件維護(hù)周期長(zhǎng)
- 項(xiàng)目進(jìn)度壓力不太大
- 被測(cè)軟件系統(tǒng)開(kāi)發(fā)比較規(guī)范,能夠保證系統(tǒng)的可測(cè)試性
- 具備大量的自動(dòng)化測(cè)試平臺(tái)
- 測(cè)試人員具備較強(qiáng)的編程能力
- 自動(dòng)化測(cè)試的流程
自動(dòng)化測(cè)試和普通的手工測(cè)試遵循的測(cè)試流程,與項(xiàng)目的具體實(shí)踐相關(guān)。一般來(lái)說(shuō),也是需要從測(cè)試計(jì)劃開(kāi)始涉及自動(dòng)化測(cè)試的。
- 測(cè)試計(jì)劃:劃定自動(dòng)化測(cè)試的范圍包含哪些需求,涉及到哪些測(cè)試過(guò)程
- 測(cè)試策略:確定自動(dòng)化測(cè)試的工具、編程方案、代碼管理、測(cè)試重點(diǎn)
- 測(cè)試設(shè)計(jì):使用測(cè)試設(shè)計(jì)方法對(duì)被測(cè)試的需求進(jìn)行設(shè)計(jì),得出測(cè)試的測(cè)試點(diǎn)、用例思維導(dǎo)圖等
- 測(cè)試實(shí)施:根據(jù)測(cè)試設(shè)計(jì)進(jìn)行用例編寫,并且將測(cè)試用例用編程的方式實(shí)現(xiàn)測(cè)試腳本
- 測(cè)試執(zhí)行:執(zhí)行測(cè)試用例,運(yùn)行測(cè)試腳本,生成測(cè)試結(jié)果
1.2 自動(dòng)化測(cè)試工具
基于Web UI的自動(dòng)化測(cè)試工具主要有兩大類:付費(fèi)的商業(yè)版工具和免費(fèi)使用的開(kāi)源版工具。典型的有兩種:
-
UFT,QTP被惠普收購(gòu)以后的新名稱。
- 通過(guò)程序的錄制,可以實(shí)現(xiàn)測(cè)試的編輯
- 錄制的測(cè)試腳本是 VBScript 語(yǔ)法
- 成熟版的商業(yè)付費(fèi)工具
- 工具比較龐大,對(duì)具體的項(xiàng)目定制測(cè)試有難度
-
SELENIUM,本次選擇的開(kāi)源工具
- 本身不是測(cè)試工具,只是模擬瀏覽器操作的工具
- 背后有 Google 維護(hù)源代碼
- 支持全部主流的瀏覽器
- 支持主流的編程語(yǔ)言,包括:Java、Python、C#、PHP、Ruby、JavaScript等
- 工具很小,可以實(shí)現(xiàn)對(duì)測(cè)試項(xiàng)目的定制測(cè)試方案
- 基于標(biāo)準(zhǔn)的 WebDriver 語(yǔ)法規(guī)范
Selenium 基本介紹
Selenium`是開(kāi)源的自動(dòng)化測(cè)試工具,它主要是用于Web 應(yīng)用程序的自動(dòng)化測(cè)試,不只局限于此,同時(shí)支持所有基于web 的管理任務(wù)自動(dòng)化。
-
Selenium官網(wǎng)的介紹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 官網(wǎng):http://seleniumhq.org/
- Selenium Github 主頁(yè):https://github.com/SeleniumHQ/selenium
Selenium 是用于測(cè)試 Web 應(yīng)用程序用戶界面 (UI) 的常用框架。它是一款用于運(yùn)行端到端功能測(cè)試的超強(qiáng)工具。您可以使用多個(gè)編程語(yǔ)言編寫測(cè)試,并且 Selenium 能夠在一個(gè)或多個(gè)瀏覽器中執(zhí)行這些測(cè)試。
Selenium 工具集
-
Selenium IDE
Selenium IDE (集成開(kāi)發(fā)環(huán)境) 是一個(gè)創(chuàng)建測(cè)試腳本的原型工具。它是一個(gè) Firefox 插件,實(shí)現(xiàn)簡(jiǎn)單的瀏覽器操作的錄制與回放功能,提供創(chuàng)建自動(dòng)化測(cè)試的建議接口。Selenium IDE 有一個(gè)記錄功能,能記錄用戶的操作,并且能選擇多種語(yǔ)言把它們導(dǎo)出到一個(gè)可重用的腳本中用于后續(xù)執(zhí)行。
-
Selenium RC
Selenium RC 是selenium 家族的核心工具,Selenium RC 支持多種不同的語(yǔ)言編寫自動(dòng)化測(cè)試腳本,通過(guò)selenium RC 的服務(wù)器作為代理服務(wù)器去訪問(wèn)應(yīng)用從而達(dá)到測(cè)試的目的。
selenium RC 使用分Client Libraries 和Selenium Server。
- Client Libraries 庫(kù)主要主要用于編寫測(cè)試腳本,用來(lái)控制selenium Server 的庫(kù)。
- Selenium Server 負(fù)責(zé)控制瀏覽器行為,總的來(lái)說(shuō),Selenium Server 主要包括3 個(gè)部分:Launcher、Http Proxy、Core。
-
Selenium Grid
Selenium Grid 使得 Selenium RC 解決方案能提升針對(duì)大型的測(cè)試套件或者哪些需要運(yùn)行在多環(huán)境的測(cè)試套件的處理能力。Selenium Grid 能讓你并行的運(yùn)行你的測(cè)試,也就是說(shuō),不同的測(cè)試可以同時(shí)跑在不同的遠(yuǎn)程機(jī)器上。這樣做有兩個(gè)優(yōu)勢(shì),首先,如果你有一個(gè)大型的測(cè)試套件,或者一個(gè)跑的很慢的測(cè)試套件,你可以使用 Selenium Grid 將你的測(cè)試套件劃分成幾份同時(shí)在幾個(gè)不同的機(jī)器上運(yùn)行,這樣能顯著的提升它的性能。同時(shí),如果你必須在多環(huán)境中運(yùn)行你的測(cè)試套件,你可以獲得多個(gè)遠(yuǎn)程機(jī)器的支持,它們將同時(shí)運(yùn)行你的測(cè)試套件。在每種情況下,Selenium Grid 都能通過(guò)并行處理顯著地縮短你的測(cè)試套件的處理時(shí)間。
-
Selenium WebDriver
WebDriver 是 Selenium 2 主推的工具,事實(shí)上WebDriver是Selenium RC的替代品,因?yàn)镾elenium需要保留向下兼容性的原因,在 Selenium 2 中, Selenium RC才沒(méi)有被徹底的拋棄,如果使用Selenium開(kāi)發(fā)一個(gè)新的自動(dòng)化測(cè)試項(xiàng)目,那么我們強(qiáng)烈推薦使用Selenium2 的 WebDriver進(jìn)行編碼。另外, 在Selenium 3 中,Selenium RC 被移除了。
自動(dòng)化編程語(yǔ)言Python選擇
- 測(cè)試人員的編程能力普遍不是很強(qiáng),而Python作為一種腳本語(yǔ)言,不僅功能強(qiáng)大,而且語(yǔ)法優(yōu)美,支持多種自動(dòng)化測(cè)試工具,而且學(xué)習(xí)上手比較容易。
- 對(duì)于有一定編程基礎(chǔ)的人員,使用Python作為自動(dòng)化測(cè)試的語(yǔ)言可以非常順暢的轉(zhuǎn)換,幾乎沒(méi)有學(xué)習(xí)成本。同時(shí)Python是標(biāo)準(zhǔn)的面向?qū)ο蟮木幊陶Z(yǔ)言,對(duì)于C#、Java等面向?qū)ο蟮恼Z(yǔ)言有著非常好的示例作用,通過(guò)Python的示例可以非常輕松的觸類旁通,使用其他語(yǔ)言進(jìn)行Selenium2.0的WebDriver的使用。
使用的工具集
- IDE: Jetbrains PyCharm
- 語(yǔ)言: Python
- 工具: Selenium WebDriver
- 源代碼管理: SVN/Git
JetBrains PyCharm 使用
- JetBrains PyCharm 的介紹
PyCharm 是 JetBrains 公司針對(duì)Python推出的IDE(Integrated Development Environment,集成開(kāi)發(fā)環(huán)境)。是目前最好的Python IDE之一。目前包含了兩個(gè)版本:
- 社區(qū)版,Community Edition
- 專業(yè)版,Professional Edition
- 付費(fèi)
- 比社區(qū)版主要多了Web開(kāi)發(fā)框架
我們推薦使用免費(fèi)的社區(qū)版本,進(jìn)行Python腳本的編寫和自動(dòng)化測(cè)試執(zhí)行。
PyCharm可以在官網(wǎng)下載,http://www.jetbrains.com
Selenium 的環(huán)境搭建
在 Windows 搭建和部署 Selenium 工具
先安裝python
-
安裝 Selenium 工具包
由于 安裝好的 Python 默認(rèn)有
pipPython 包管理工具,可以通過(guò)pip非常方便的安裝 Selenium。
```
pip install selenium
```
```
pip install -U selenium
```
當(dāng)然,可以事先下載 Selenium 的 Python 安裝包,再進(jìn)行手動(dòng)安裝。
官方下載地址:https://pypi.python.org/pypi/selenium
```
python setup.py install
```
?
-
配置瀏覽器和驅(qū)動(dòng)
Selenium 3 對(duì)于所有的瀏覽器都需要安裝驅(qū)動(dòng),本文以 Chrome 和 Firefox、IE為例設(shè)置瀏覽器和驅(qū)動(dòng)。
ChromeDriver下載地址:http://chromedriver.storage.googleapis.com/index.html
ChromeDriver 與 Chrome 對(duì)應(yīng)關(guān)系表:
ChromeDriver版本 | 支持的Chrome版本 |
-|-|
v2.31| v58-60 |
v2.30 |v58-60 |
v2.29 |v56-58 |
GeckoDriver下載地址:https://github.com/mozilla/geckodriver/releases
GeckoDriver 與 Firefox 的對(duì)應(yīng)關(guān)系表:
GeckoDriver版本 |支持的Firefox版本 |
-|-|
v0.18.0| v56 |
v0.17.0 |v55 |
IEDriverServer下載地址:http://selenium-release.storage.googleapis.com/index.html
IEDriverServer 的版本需要與 Selenium 保持嚴(yán)格一致。
**瀏覽器驅(qū)動(dòng)的配置**
- 首先,將下載好的對(duì)應(yīng)版本的瀏覽器安裝。
- 其次,在 Python 的根目錄中,放入瀏覽器驅(qū)動(dòng)。
- 最好再重啟電腦,一般情況下不重啟也可以的。
?
1.3 Selenium 的最簡(jiǎn)腳本
通過(guò)上一節(jié)的環(huán)境安裝成功以后,我們可以進(jìn)行第一個(gè)對(duì)Selenium 的使用,就是最簡(jiǎn)腳本編寫。腳本如下:
# 聲明一個(gè)司機(jī),司機(jī)是個(gè)Chrome類的對(duì)象
driver = webdriver.Chrome()
# 讓司機(jī)加載一個(gè)網(wǎng)頁(yè)
driver.get("http://demo.xxx.com")
# 給司機(jī)3秒鐘去打開(kāi)
sleep(3)
# 開(kāi)始登錄
# 1. 讓司機(jī)找用戶名的輸入框
we_account = driver.find_element_by_css_selector('#account')
we_account.clear()
we_account.send_keys("demo")
# 2. 讓司機(jī)找密碼的輸入框
we_password = driver.find_element_by_css_selector('#password')
we_password.clear()
we_password.send_keys("demo")
# 3. 讓司機(jī)找 登錄按鈕 并 單擊
driver.find_element_by_css_selector('#submit').click()
sleep(3)
實(shí)際上一段20行的代碼,也不能算太少了。但是這段代碼的使用,確實(shí)體現(xiàn)了 Selenium 的最簡(jiǎn)單的使用。這些代碼有開(kāi)發(fā)基礎(chǔ)的同學(xué),一看都懂。
注意:Chrome 是 WebDriver 的子類,是 WebDriver 類的一種
1.4 Selenium WebDriver API 的使用
通過(guò)上述最簡(jiǎn)腳本的使用,我們可以來(lái)進(jìn)一步了解 Selenium 的使用。事實(shí)上,上一節(jié)用的,便是 Selenium 的 WebDriver API。
Selenium WebDriver API 官方參考:http://seleniumhq.github.io/selenium/docs/api/py/
具體API文檔地址:https://seleniumhq.github.io/selenium/docs/api/py/api.html
控制瀏覽器
瀏覽器的控制也是自動(dòng)化測(cè)試的一個(gè)基本組成部分,我們可以將瀏覽器最大化,設(shè)置瀏覽器的高度和寬度以及對(duì)瀏覽器進(jìn)行導(dǎo)航操作等。
# 瀏覽器打開(kāi)網(wǎng)址
driver.get("https://www.baidu.com")
# 瀏覽器最大化
driver.maximize_window()
# 設(shè)置瀏覽器的高度為800像素,寬度為480像素
driver.set_window_size(480, 800)
# 瀏覽器后退
driver.back()
# 瀏覽器前進(jìn)
driver.forward()
# 瀏覽器關(guān)閉
driver.close()
# 瀏覽器退出
driver.quit()
元素定位操作
WebDriver提供了一系列的定位符以便使用元素定位方法。常見(jiàn)的定位符有以下幾種:
- id
- name
- class name
- tag
- link text
- partial link text
- xpath
- css selector
那么我們以下的操作將會(huì)基于上述的定位符進(jìn)行定位操作。
對(duì)于元素的定位,WebDriver API可以通過(guò)定位簡(jiǎn)單的元素和一組元素來(lái)操作。在這里,我們需要告訴Selenium如何去找元素,以至于他可以充分的模擬用戶行為,或者通過(guò)查看元素的屬性和狀態(tài),以便我們執(zhí)行一系列的檢查。
在Selenium2中,WebDriver提供了多種多樣的find_element_by方法在一個(gè)網(wǎng)頁(yè)里面查找元素。這些方法通過(guò)提供過(guò)濾標(biāo)準(zhǔn)來(lái)定位元素。當(dāng)然WebDriver也提供了同樣多種多樣的find_elements_by的方式去定位多個(gè)元素。
盡管上述的方式,可以進(jìn)行元素定位,實(shí)際上我們也是更多的用組合的方式進(jìn)行元素定位。
| 方法Method | 描述Description | 參數(shù)Argument | 示例Example |
|---|---|---|---|
id |
該方法通過(guò)ID的屬性值去定位查找單個(gè)元素 | id: 需要被查找的元素的ID | find_element_by_id('search') |
name |
該方法通過(guò)name的屬性值去定位查找單個(gè)元素 | name: 需要被查找的元素的名稱 | find_element_by_name('q') |
class name |
該方法通過(guò)class的名稱值去定位查找單個(gè)元素 | class_name: 需要被查找的元素的類名 | find_element_by_class_name('input-text') |
tag_name |
該方法通過(guò)tag的名稱值去定位查找單個(gè)元素 | tag: 需要被查找的元素的標(biāo)簽名稱 | find_element_by_tag_name('input') |
link_text |
該方法通過(guò)鏈接文字去定位查找單個(gè)元素 | link_text: 需要被查找的元素的鏈接文字 | find_element_by_link_text('Log In') |
partial_link_text |
該方法通過(guò)部分鏈接文字去定位查找單個(gè)元素 | link_text: 需要被查找的元素的部分鏈接文字 | find_element_by_partial_link_text('Long') |
xpath |
該方法通過(guò)XPath的值去定位查找單個(gè)元素 | xpath: 需要被查找的元素的xpath | find_element_by_xpath('//*[@id="xx"]/a') |
css_selector |
該方法通過(guò)CSS選擇器去定位查找單個(gè)元素 | css_selector: 需要被查找的元素的ID | find_element_by_css_selector('#search') |
而find_elements_by的方法依據(jù)匹配的具體標(biāo)準(zhǔn)返回一系列的元素。
下面代碼通過(guò)ID的屬性值去定義一個(gè)查找文本框的查找:
<input id="search" type="text" name="q" value=""
class="input-text" maxlength="128" autocomplete="off"/>
根據(jù)上述代碼,這里我們使用find_element_by_id()的方法去查找搜索框并且檢查它的最大長(zhǎng)度maxlength屬性。我們通過(guò)傳遞ID的屬性值作為參數(shù)去查找,參考如下的代碼示例:
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()方法,將會(huì)返回所有的具有相同ID屬性值的一系列元素。
這里還是根據(jù)上述ID查找的HTML代碼,使用find_element_by_name的方法進(jìn)行查找。參考如下的代碼示例:
# get the search textbox
self.search_field = self.driver.find_element_by_name("q")
同樣,如果使用find_elements_by_name()方法,將會(huì)返回所有的具有相同name屬性值的一系列元素。
依據(jù)class name查找
除了上述的ID和name的方式查找,我們還可以使用class name的方式進(jìn)行查找和定位。
事實(shí)上,通過(guò)ID,name或者類名class name查找元素是最提倡推薦的和最快的方式。
<button type="submit" title="Search" class="button">
<span><span>Search</span></span>
</button>
根據(jù)上述代碼,使用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())
其他方式都可以參考jquery或一些爬蟲(chóng)關(guān)于html節(jié)點(diǎn)查找的方法。
依據(jù)XPath進(jìn)行查找
XPath是一種在XML文檔中搜索和定位節(jié)點(diǎn)node的一種查詢語(yǔ)言。所有的主流Web瀏覽器都支持XPath。
常用的XPath的方法有starts-with(),contains()和ends-with()等
若想要了解更多關(guān)于XPath的內(nèi)容,請(qǐng)查看http://www.w3schools.com/XPath/
如下有一段HTML代碼,其中里面的<img>沒(méi)有使用ID,name或者類屬性,所以我們無(wú)法使用之前的方法。這里我們可以通過(guò)<img>的alt屬性,定位到指定的tag。
<ul class="promos">
<li>
<a >
<img src="/media/wysiwyg/homepage-three-column-promo-
01B.png" alt="Physical & Virtual Gift Cards">
</a>
</li>
<li>
<a >
<img src="/media/wysiwyg/homepage-three-column-promo-
02.png" alt="Shop Private Sales - Members Only">
</a>
</li>
<li>
<a href="http://www.9999.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("http://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)
當(dāng)然,如果使用find_elements_by_xpath()的方法,將會(huì)返回所有匹配了XPath查詢的元素。
依據(jù)CSS選擇器進(jìn)行查找
CSS是一種設(shè)計(jì)師用來(lái)描繪HTML文檔的視覺(jué)的層疊樣式表。一般來(lái)說(shuō)CSS用來(lái)定位多種多樣的風(fēng)格,同時(shí)可以用來(lái)是同樣的標(biāo)簽使用同樣的風(fēng)格等。
<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>
我們來(lái)創(chuàng)建一個(gè)測(cè)試,驗(yàn)證這些消息是否正確。
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 元素會(huì)創(chuàng)建包含另外一個(gè)文檔的內(nèi)聯(lián)框架(即行內(nèi)框架)。
在一個(gè)<html>中,包含了另一個(gè)<html>
示例
<html>
<head>
<title>iframe示例</title>
</head>
<body>
<h1>
這里是H1,標(biāo)記了標(biāo)題
</h1>
<p>
這里是段落,標(biāo)記一個(gè)段落,屬于外層
</p>
<div>
<iframe id="iframe-1">
<html>
<body>
<p>
這里是個(gè)段落,屬于內(nèi)層,內(nèi)聯(lián)框架中的
</p>
<div id="div-1">
<p class="hahahp">
這里是div中的段落,需要被定位
</p>
</div>
</body>
</html>
</iframe>
</div>
</body>
</html>
需要定位上面示例中的:
<p>這里是div中的段落,需要被定位</p>
如下是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....
## 退出剛剛切換進(jìn)去的 iframe
driver.switch_to.default_content()
特殊 Select 操作
<select>是選擇列表Select 是個(gè)selenium的類
selenium.webdriver.support.select.Select
<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類的構(gòu)造方法,實(shí)例化一個(gè)對(duì)象 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')
組合操作
自動(dòng)化經(jīng)驗(yàn)的積累,需要100%按照手工的步驟進(jìn)行操作。
比如步驟如下:
- 點(diǎn)擊一個(gè)
<a id="customer_chosen"> - 自動(dòng)產(chǎn)生了一個(gè)
<ul id="customer_list"> - 點(diǎn)擊
<ul>的第五個(gè)<li>
代碼示例
driver.find_element_by_css_selector('#customer_chosen').click()
sleep(1)
driver.find_element_by_css_selector('#customer_list > li:nth-child(5)').click()
鼠標(biāo)事件操作
Web測(cè)試中,有關(guān)鼠標(biāo)的操作,不只是單擊,有時(shí)候還要做右擊、雙擊、拖動(dòng)等操作。這些操作包含在ActionChains類中。
常用的鼠標(biāo)方法:
- context_click() # 右擊
- double_click() # 雙擊
- drag_and_drop() # 拖拽
- move_to_element() # 鼠標(biāo)停在一個(gè)元素上
- click_and_hold() # 按下鼠標(biāo)左鍵在一個(gè)元素上
例子:
# 方法模擬鼠標(biāo)右鍵,參考代碼如下:
# 引入ActionChains 類
from selenium.webdriver.common.action_chains import ActionChains
...
# 定位到要右擊的元素
right =driver.find_element_by_xpath("xx")
# 對(duì)定位到的元素執(zhí)行鼠標(biāo)右鍵操作
ActionChains(driver).context_click(right).perform()
...
# 定位到要雙擊的元素
double = driver.find_element_by_xpath("xxx")
# 對(duì)定位到的元素執(zhí)行鼠標(biāo)雙擊操作
ActionChains(driver).double_click(double).perform()
鍵盤事件操作
鍵盤操作經(jīng)常處理的如下:
| 代碼 | 描述 | ||
|---|---|---|---|
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') |
復(fù)制(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")
# 輸入框輸入內(nèi)容
driver.find_element_by_id("kw").send_keys("selenium")
time.sleep(3)
# 刪除多輸入的一個(gè)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 全選輸入框內(nèi)容
driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'a')
截圖操作
截圖的方法:save_screenshot(file)
1.5 unittest 單元測(cè)試框架
在上一節(jié),我們對(duì) Selenium WebDriver 的使用,僅僅停留在讓網(wǎng)頁(yè)自動(dòng)的進(jìn)行操作的階段,并沒(méi)有對(duì)任何一個(gè)步驟進(jìn)行“檢查”。當(dāng)然,這樣沒(méi)有“檢查”的操作,實(shí)際上是沒(méi)有測(cè)試意義的。那么第一項(xiàng),我們需要解決的便是“檢查”的問(wèn)題。
所謂“檢查”,實(shí)際上就是斷言。對(duì)需要檢查的步驟操作,通過(guò)對(duì)預(yù)先設(shè)置的期望值,和執(zhí)行結(jié)果的實(shí)際值之間的對(duì)比,得到測(cè)試的結(jié)果。在這里,我們并不需要單獨(dú)的寫 if 語(yǔ)句進(jìn)行各種判定,而是可以使用編程語(yǔ)言中對(duì)應(yīng)的單元測(cè)試框架,即可解決好此類問(wèn)題。
目前 Java 語(yǔ)言主流的單元測(cè)試框架有 JUnit 和 TestNG。Python 語(yǔ)言主流的單元測(cè)試框架有 unittest 。本小節(jié)的內(nèi)容,主要介紹 unittest 的使用,探討單元測(cè)試框架如何幫助自動(dòng)化測(cè)試。
接下來(lái)我們將會(huì)使用 Python 語(yǔ)言的unittest框架展開(kāi)“檢查”。unittest框架的原本的名字是PyUnit。是從JUnit 這樣一個(gè)被廣泛使用的經(jīng)典的Java應(yīng)用開(kāi)發(fā)的單元測(cè)試框架創(chuàng)造而來(lái)。類似的框架還有NUnit(.Net開(kāi)發(fā)的單元測(cè)試框架)等。我們可以使用unittest框架為任意Python項(xiàng)目編寫可理解的單元測(cè)試集合。現(xiàn)在這個(gè)unittest已經(jīng)作為Python的標(biāo)準(zhǔn)庫(kù)模塊發(fā)布。我們安裝完P(guān)ython以后,便可以直接使用unittest。
使用unittest需要以下簡(jiǎn)單的三步:
- 引入unittest模組
- 繼承unittest.TestCase基類
- 測(cè)試方法以
test開(kāi)頭
unittest 并未使用 Java 語(yǔ)言常見(jiàn)的注解方式,依舊停留在 比較早期的 Java 版本中依靠方法名稱進(jìn)行識(shí)別的方式。主要有以下兩個(gè)固定名字的方法:
- setUp():在每個(gè)測(cè)試方法運(yùn)行前,執(zhí)行。是測(cè)試前置條件。
- tearDown():在每個(gè)測(cè)試方法運(yùn)行后執(zhí)行,是測(cè)試清理操作。
具體的代碼如下:
## 引入unittest模組
import unittest
## 定義測(cè)試類,名字為DemoTests
## 該類必須繼承unittest.TestCase基類
class DemoTests(unittest.TestCase):
## 使用'@'修飾符,注明該方法是類的方法
## setUpClass方法是在執(zhí)行測(cè)試之前需要先調(diào)用的方法
## 是開(kāi)始測(cè)試前的初始化工作
@classmethod
def setUpClass(cls):
print("call setUpClass()")
## 每一個(gè)測(cè)試開(kāi)始前的預(yù)置條件
def setUp(self):
print("call setUp()")
## 每一個(gè)測(cè)試結(jié)束以后的清理工作
def tearDown(self):
print("call tearDown()")
## 測(cè)試一(務(wù)必以test開(kāi)頭)
def test_01(self):
print("call test_01()")
pass
## 測(cè)試三(務(wù)必以test開(kāi)頭)
def test_02(self):
print("call test_02()")
pass
## 測(cè)試三(務(wù)必以test開(kāi)頭)
def test_03(self):
print("call test_03()")
pass
## tearDownClass方法是執(zhí)行完所有測(cè)試后調(diào)用的方法
## 是測(cè)試結(jié)束后的清除工作
@classmethod
def tearDownClass(cls):
print("call tearDownClass()")
# 執(zhí)行測(cè)試主函數(shù)
if __name__ == '__main__':
## 執(zhí)行main全局方法,將會(huì)執(zhí)行上述所有以test開(kāi)頭的測(cè)試方法
unittest.main(verbosity=2)
需要注意步驟:
- 引入 unittest 模組
- 繼承 unittest.TestCase 類
- 做測(cè)試用例的方法,方法以 test_ 開(kāi)頭
- 附加 setUp(), tearDown(), 在每個(gè) test_ 方法執(zhí)行前后 進(jìn)行執(zhí)行
- 附加 setUpClass(), tearDownClass()
需要在 類實(shí)例化的對(duì)象,運(yùn)行的開(kāi)頭和結(jié)尾進(jìn)行執(zhí)行。
加了星號(hào)(*)的步驟,可以不用。
上述代碼運(yùn)行結(jié)果如下:
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
清晰的單元測(cè)試框架,提供 TestCase, TestSuite, TextTestRunner 等基本類
unittest 是 原生 Python 的一部分
unittest 有第三方可用的 HTML 庫(kù),可以輕松的生成 測(cè)試報(bào)告
-
unittest 的斷言配置使用
unittest 的斷言,屬于
TestCase類,只要繼承了該類,均可以通過(guò) self調(diào)用斷言方法 Method 檢查條件
assertEqual(a, b [, msg])a == b,msg可選,用來(lái)解釋失敗的原因assertNotEqual(a, b [, msg]a != b,msg可選,用來(lái)解釋失敗的原因assertTrue(x [, msg])x 是真,msg可選,用來(lái)解釋失敗的原因assertFalse(x [, msg])x 是假,msg可選,用來(lái)解釋失敗的原因assertIsNot(a, b [, msg])a 不是 b,msg可選,用來(lái)解釋失敗的原因
1.6 為什么需要封裝 Selenium
-
什么是封裝
封裝是一個(gè)面向?qū)ο缶幊痰母拍?,是面向?qū)ο缶幊痰暮诵膶傩?,通過(guò)將代碼內(nèi)部實(shí)現(xiàn)進(jìn)行密封和包裝,從而簡(jiǎn)化編程。對(duì)Selenium進(jìn)行封裝的好處主要有如下三個(gè)方面:
- 使用成本低
- 不需要要求所有的測(cè)試工程師會(huì)熟練使用Selenium,而只需要會(huì)使用封裝以后的代碼
- 不需要對(duì)所有的測(cè)試工程師進(jìn)行完整培訓(xùn)。也避免工作交接的成本。
- 測(cè)試人員使用統(tǒng)一的代碼庫(kù)
- 維護(hù)成本低
- 通過(guò)封裝,在代碼發(fā)生大范圍變化和遷移的時(shí)候,不需要維護(hù)所有代碼,只需要變更封裝的部分即可
- 維護(hù)代碼不需要有大量的工程師,只需要有核心的工程師進(jìn)行封裝的維護(hù)即可
- 代碼安全性
- 對(duì)作為第三方的Selenium進(jìn)行封裝,是代碼安全的基礎(chǔ)。
- 對(duì)于任何的代碼的安全隱患,必須由封裝來(lái)解決,使得風(fēng)險(xiǎn)可控。
- 使用者并不知道封裝內(nèi)部的代碼結(jié)構(gòu)。
1.7 如何封裝
這里面向的用戶是開(kāi)發(fā)者,有一定基礎(chǔ)的,特別是面向?qū)ο箝_(kāi)發(fā)基礎(chǔ)的開(kāi)發(fā)者。封裝,最簡(jiǎn)單直接就是函數(shù)、方法、類。這里不再?gòu)?fù)述。
1.8 Page-Object設(shè)計(jì)模式介紹
-
Page-Object設(shè)計(jì)模式的本質(zhì)
Page Object設(shè)計(jì)模式是Selenium自動(dòng)化測(cè)試項(xiàng)目的最佳設(shè)計(jì)模式之一,強(qiáng)調(diào)測(cè)試、邏輯、數(shù)據(jù)和驅(qū)動(dòng)相互分離。
Page Object模式是Selenium中的一種測(cè)試設(shè)計(jì)模式,主要是將每一個(gè)頁(yè)面設(shè)計(jì)為一個(gè)Class,其中包含頁(yè)面中需要測(cè)試的元素(按鈕,輸入框,標(biāo)題等),這樣在Selenium測(cè)試頁(yè)面中可以通過(guò)調(diào)用頁(yè)面類來(lái)獲取頁(yè)面元素,這樣巧妙的避免了當(dāng)頁(yè)面元素id或者位置變化時(shí),需要改測(cè)試頁(yè)面代碼的情況。當(dāng)頁(yè)面元素id變化時(shí),只需要更改測(cè)試頁(yè)Class中頁(yè)面的屬性即可。
它的好處如下:
- 集中管理元素對(duì)象,便于應(yīng)對(duì)元素的變化
- 集中管理一個(gè)page內(nèi)的公共方法,便于測(cè)試用例的編寫
- 后期維護(hù)方便,不需要重復(fù)的復(fù)制和修改代碼
具體的做法如下:
- 創(chuàng)建一個(gè)頁(yè)面的類
- 在類的構(gòu)造方法中,傳遞 WebDriver 參數(shù)。
- 在測(cè)試用例的類中,實(shí)例化頁(yè)面的類,并且傳遞在測(cè)試用例中已經(jīng)實(shí)例化的WebDriver對(duì)象。
- 在頁(yè)面的類中,編寫該頁(yè)面的所有操作的方法
- 在測(cè)試用例的類中,調(diào)用這些方法
-
Page 如何劃分
一般通過(guò)繼承的方式,進(jìn)行按照實(shí)際Web頁(yè)面進(jìn)行劃分
-
Page-Object 類如何實(shí)現(xiàn)
實(shí)現(xiàn)的示例
-
Page 基類
- 設(shè)計(jì)了一個(gè)基本的 Page類,以便所有的頁(yè)面進(jìn)行繼承,該類標(biāo)明了一個(gè)sub page類的基本功能和公共的功能。
- 全局變量: self.base_driver,讓所有的子類都使用的。
# 基類的變量,所有繼承的類,都可以使用 base_driver = None構(gòu)造方法:
傳遞 driver的構(gòu)造方法
# 方法 def __init__(self, driver: BoxDriver): """ 構(gòu)造方法 :param driver: ":BoxDriver" 規(guī)定了 driver 參數(shù)類型 """ self.base_driver = driver- 私有的常量:存放元素的定位符
-
```python
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"
```
- 成員方法:
- 每個(gè)子類都需要的系統(tǒng)功能:
- open
```pypthon
def open(self, url):
"""
打開(kāi)頁(yè)面
:param url:
:return:
"""
self.base_driver.navigate(url)
self.base_driver.maximize_window()
sleep(2)
```
- 所有子類(頁(yè)面)都具有的業(yè)務(wù)功能
- select\_app
- logout
- Sub Pages(s)子類
- 具體的頁(yè)面的類,定義了某個(gè)具體的頁(yè)面的功能
- 必須繼承基類
```
class MainPage(BasePage):
```
- 特定頁(yè)面的業(yè)務(wù)
- 使用基類的 `self.base_driver` 成員變量
- Tests 類
- 這部分描述的是具體的測(cè)試用例。
- 聲明全局變量
```
base_driver = None
base_url = None
main_page = None
```
- 調(diào)用各種頁(yè)面(pages)
- 實(shí)例化Page
```python
self.main_page = MainPage(self.base_driver)
```
- 使用page的對(duì)象,調(diào)用成員方法
```python
self.main_page.open(self.base_url)
self.main_page.change_language(lang)
```
2. 構(gòu)建測(cè)試方案
2.1 數(shù)據(jù)驅(qū)動(dòng)在自動(dòng)化測(cè)試中的應(yīng)用
-
什么是數(shù)據(jù)驅(qū)動(dòng)
主要的數(shù)據(jù)驅(qū)動(dòng)方式有兩種:
- 通過(guò) 文本文件或者 Excel 文件存儲(chǔ)數(shù)據(jù),并通過(guò)程序讀取數(shù)據(jù),遍歷所有的行
- 通過(guò)數(shù)據(jù)庫(kù)存儲(chǔ)數(shù)據(jù),并通過(guò)程序和 SQL 腳本讀取數(shù)據(jù),遍歷所有的行
通過(guò) CSV 文件 或者 MySQL 數(shù)據(jù)庫(kù),是主流的數(shù)據(jù)驅(qū)動(dòng)方式。當(dāng)然數(shù)據(jù)驅(qū)動(dòng)也可以結(jié)合單元測(cè)試框架的參數(shù)化測(cè)試進(jìn)行編寫(此部分本文不做具體描述)。
無(wú)論使用了 哪一種(CSV 或者 MySQL),讀取數(shù)據(jù)后都要進(jìn)行遍歷操作。
- 使用 csv
```python
import csv
csv_file = open("xxx.csv", "r", encoding="utf8")
csv_data = csv.reader(csv_file)
for row in csv_data:
# 進(jìn)行測(cè)試
# 使用字典類型
data_to_test = {
"key1": row[0],
"key2": row[1]
}
csv_file.close()
```
- 使用 MySQL
```python
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:
# 進(jìn)行測(cè)試
# 使用字典類型
data_to_test = {
"key1": row[0],
"key2": row[1]
}
cur.close()
connect.close()
```
-
需要掌握的知識(shí)點(diǎn):
- python的字典類型
dict類型 - python的讀寫文件
- python的讀寫數(shù)據(jù)庫(kù)
- for循環(huán)
- 注意資源的釋放
- 關(guān)閉數(shù)據(jù)庫(kù)游標(biāo)和連接
- 關(guān)閉文件
- python的字典類型
2.2 測(cè)試方案的編碼實(shí)現(xiàn)
- main.py 測(cè)試入口
- runner.py 測(cè)試運(yùn)行器
- cases 測(cè)試用例
- pages 測(cè)試頁(yè)面
- base 底層封裝與驅(qū)動(dòng)
2.3 測(cè)試報(bào)告的生成
如何生成測(cè)試報(bào)告
測(cè)試報(bào)告的種類
-
HTML 測(cè)試報(bào)告的生成
HTML測(cè)試報(bào)告需要引入HTMLTestRunner
HTMLTestRunner是基于Python2.7的,我們的課程講義基于Python3.x,那么需要對(duì)這個(gè)文件做一定的修改。
測(cè)試的示例代碼如下
```python
# 聲明一個(gè)測(cè)試套件
suite = unittest.TestSuite()
# 添加測(cè)試用例到測(cè)試套件
suite.addTest(RanzhiTests("test_ranzhi_login"))
# 創(chuàng)建一個(gè)新的測(cè)試結(jié)果文件
buf = open("./result.html", "wb")
# 聲明測(cè)試運(yùn)行的對(duì)象
runner = HTMLTestRunner.HTMLTestRunner(stream=buf,
title="Ranzhi Test Result",
description="Test Case Run Result")
# 運(yùn)行測(cè)試,并且將結(jié)果生成為HTML
runner.run(suite)
# 關(guān)閉文件輸出
buf.close()
```