selenium自動(dòng)化測試基礎(chǔ)
- 1. 使用測試工具
- 2. 構(gòu)建測試方案
原文閱讀對象是針對測試人員碰缔,測試人員普遍開發(fā)能力偏弱萤彩,所以講的比較瑣碎膘掰,這里做了一定的刪減和改寫摹芙,主要針對測試主管或有一定經(jīng)驗(yàn)的開發(fā)人員或負(fù)責(zé)人嵌莉,快速了解及考慮使用selenium自動(dòng)化測試方案苛茂。
自動(dòng)化測試并不屬于新鮮的事物,或者說自動(dòng)化測試的各種方法論已經(jīng)層出不窮族操,但是苛坚,能夠在項(xiàng)目中持之以恒的實(shí)踐自動(dòng)化測試的團(tuán)隊(duì),卻依舊不是非常多色难。有的團(tuán)隊(duì)知道怎么做泼舱,做的還不夠好;有的團(tuán)隊(duì)還正在探索和摸索怎么做枷莉,甚至還有一些多方面的技術(shù)上和非技術(shù)上的舊系統(tǒng)需要重構(gòu)……
本文從
使用
和實(shí)踐
兩個(gè)視角娇昙,嘗試對基于Web UI
自動(dòng)化測試做細(xì)致的分析和解讀,給各位去思考和實(shí)踐做一點(diǎn)引路依沮,以便各團(tuán)隊(duì)能找到更好的方式涯贞。
1. 使用測試工具
在開始具體的自動(dòng)化測試之前,我們需要做好更多的準(zhǔn)備危喉,包括以下幾個(gè)方面:
- 認(rèn)識自動(dòng)化測試
- 準(zhǔn)備自動(dòng)化測試工具
- 使用有效的方式
- 針對具體的測試對象
1.1 自動(dòng)化測試?yán)碚摻榻B
自動(dòng)化測試不再是一個(gè)陌生的話題宋渔,作為測試實(shí)踐活動(dòng)的一部分,我們首先分析一下自動(dòng)化測試的方方面面辜限。
自動(dòng)化測試的4W1H
-
WHAT
- 什么是自動(dòng)化測試《軟件測試藝術(shù)》一書中皇拣,給出了測試的定義:
“程序測試是為了發(fā)現(xiàn)錯(cuò)誤而執(zhí)行的過程。”
自動(dòng)化測試:以人為驅(qū)動(dòng)的測試行為轉(zhuǎn)化為機(jī)器執(zhí)行的一種過程
自動(dòng)化測試氧急,就是把手工進(jìn)行的測試過程颗胡,轉(zhuǎn)變成機(jī)器自動(dòng)執(zhí)行的測試過程。該過程吩坝,依舊是為了發(fā)現(xiàn)錯(cuò)誤而執(zhí)行毒姨。因此自動(dòng)化測試的關(guān)鍵在于“自動(dòng)化”三個(gè)字。自動(dòng)化測試的內(nèi)容钉寝,也就相應(yīng)的轉(zhuǎn)變成如何“自動(dòng)化”去實(shí)現(xiàn)原本手工進(jìn)行的測試的過程弧呐。
通過程序,可以把手工測試嵌纲,轉(zhuǎn)變成自動(dòng)化測試俘枫。
-
WHEN
- 在什么時(shí)候開展自動(dòng)化測試自動(dòng)化測試的開展,依賴于“程序”逮走。那么程序鸠蚪,其實(shí)就是由“源代碼”構(gòu)建而來的。那么原則上师溅,只要能做出自動(dòng)化測試所需要的“程序”的時(shí)候茅信,就可以進(jìn)行自動(dòng)化測試。但往往险胰,并不是所有的“時(shí)候”都是好的“時(shí)機(jī)”汹押。從這個(gè)
W
開始矿筝,我們將會(huì)加入對于成本的顧慮起便,也正是因?yàn)椤俺杀尽钡拇嬖冢攀沟孟旅娴挠懻摻盐兊糜幸饬x榆综。所有的開銷,都是有成本的铸史。構(gòu)建成“程序”的源代碼鼻疮,也是由工程師寫出來的。那么需要考慮這個(gè)過程中的成本琳轿∨泄担基于這個(gè)考慮,在能夠比較穩(wěn)定的構(gòu)建“程序”的時(shí)候崭篡,不需要花費(fèi)太多開銷在“源代碼”的時(shí)候挪哄,就是開展自動(dòng)化測試的好時(shí)機(jī)。這個(gè)開銷包括
編寫
和修改
源代碼琉闪,而源代碼指的是構(gòu)建出用來做自動(dòng)化測試的程序
的源代碼迹炼。 -
WHERE
- 在什么地方進(jìn)行自動(dòng)化測試自動(dòng)化測試的執(zhí)行,依靠的是機(jī)器。那么自動(dòng)化測試必將在“機(jī)器”上進(jìn)行斯入。一般來說砂碉,這個(gè)機(jī)器包括桌面電腦和服務(wù)器。通過將寫好的
源代碼
部署在機(jī)器上刻两,構(gòu)建出用來做自動(dòng)化測試的"程序"增蹭,并且運(yùn)行該程序,實(shí)現(xiàn)自動(dòng)化測試磅摹。 -
WHICH
- 對什么目標(biāo)進(jìn)行自動(dòng)化測試自動(dòng)化測試的目標(biāo)沪铭,是被測試的軟件。拋開人工智能的成分偏瓤,手工測試必將在“人工智能”足夠普及和足夠“智能”之前杀怠,替代一大部分不需要“人類智能”的手工測試;以及自動(dòng)化測試會(huì)做一些手工測試無法實(shí)施的厅克,或者手工測試無法覆蓋的測試赔退。
- 不需要“人類智能”的普通手工測試
- 界面的普通操作
- 通過固定輸入和固定操作而進(jìn)行的流程化測試
- 重復(fù)的普通測試
- 手工測試無法實(shí)施或者覆蓋的
- 大量的數(shù)據(jù)的輸入
- 大量的步驟的操作
- 源代碼基本的測試
- 系統(tǒng)模塊間接口的調(diào)用測試
- ……
-
HOW
- 如何開展自動(dòng)化測試- 準(zhǔn)備測試用例
- 找到合適的自動(dòng)化測試工具
- 用準(zhǔn)確的編程形成測試腳本
- 在測試腳本中對目標(biāo)進(jìn)行“檢查”,即做斷言
- 記錄測試日志证舟,生成測試結(jié)果
和所有的其他測試一樣硕旗,自動(dòng)化測試的流程也是由“用例”執(zhí)行和“缺陷”驗(yàn)證組成。差別是需要找到合適的“工具”來替代“人手”女责。不同目標(biāo)的自動(dòng)化測試有不同的測試工具漆枚,但是任何工具都無不例外的需要“編程”的過程,實(shí)現(xiàn)“源代碼”抵知,也可以稱之為測試腳本墙基。
于是開展自動(dòng)化測試的方式基本上如下:
自動(dòng)化測試的典型金字塔原理
談到自動(dòng)化測試,就不得不提的一個(gè)人和概念就是:Martin Fowler和他的金字塔原理刷喜。首先請看金字塔原理的圖示如下:
該圖說明了三個(gè)問題:
- 自動(dòng)化測試包括三個(gè)方面:UI前端界面残制,Service服務(wù)契約和Unit底層單元
- 越是底層的測試,運(yùn)行速度越快掖疮,時(shí)間開銷越少初茶,金錢開銷越少
- 越是頂層的測試,運(yùn)行速度越慢浊闪,時(shí)間開銷越多恼布,金錢開銷越多
這是理想中的金字塔原理。
在實(shí)際的項(xiàng)目中搁宾,尤其是結(jié)合國內(nèi)的項(xiàng)目實(shí)踐折汞,其實(shí)還隱藏了另一個(gè)問題:越是頂層的測試,效果越明顯猛铅。有句話說“貴的東西字支,除了貴,其他都是好的!”能夠很清晰的闡述這個(gè)觀點(diǎn)堕伪。
金字塔原理在國內(nèi)的適應(yīng)性也有一定的問題
- 自動(dòng)化測試的起步不是特別早
- 甚至軟件測試很長一段時(shí)間都在進(jìn)行基于業(yè)務(wù)的手工測試揖庄,測試人員的代碼能力相對較弱
- 開發(fā)人員在代碼中不太習(xí)慣寫單元測試
- 近些年基于服務(wù)契約的API測試也在興起
相對來說,在基于UI前端界面的自動(dòng)化測試反倒是開展和實(shí)施的不是特別多欠雌。盡管基于界面的測試帶來的效果還是能夠立竿見影的蹄梢。對于產(chǎn)品的質(zhì)量提升,還是比較容易有保證富俄。
自動(dòng)化測試的適用范圍
自動(dòng)化測試可以涉及和試用的范圍主要在以下方面:
- 基于
Web UI
的瀏覽器應(yīng)用的界面測試 - 基于
WebService
或者WebAPI
的服務(wù)契約測試 - 基于
WCF
禁炒、.net remoting
、Spring
等框架的服務(wù)的集成測試 - 基于
APP UI
的移動(dòng)應(yīng)用界面測試 - 基于
Java
霍比、C#
等編程文件進(jìn)行的單元測試
本文集中討論第一條:基于Web UI
的瀏覽器應(yīng)用的界面測試幕袱。界面的改動(dòng)對于測試來說,具有較大的成本風(fēng)險(xiǎn)悠瞬。主要考慮以下方面:
- 任務(wù)測試明確们豌,不會(huì)頻繁變動(dòng)
- 每日構(gòu)建后的測試驗(yàn)證
- 比較頻繁的回歸測試
- 軟件系統(tǒng)界面穩(wěn)定,變動(dòng)少
- 需要在多平臺上運(yùn)行的相同測試案例浅妆、組合遍歷型的測試望迎、大量的重復(fù)任務(wù)
- 軟件維護(hù)周期長
- 項(xiàng)目進(jìn)度壓力不太大
- 被測軟件系統(tǒng)開發(fā)比較規(guī)范,能夠保證系統(tǒng)的可測試性
- 具備大量的自動(dòng)化測試平臺
- 測試人員具備較強(qiáng)的編程能力
- 自動(dòng)化測試的流程
自動(dòng)化測試和普通的手工測試遵循的測試流程凌外,與項(xiàng)目的具體實(shí)踐相關(guān)辩尊。一般來說,也是需要從測試計(jì)劃開始涉及自動(dòng)化測試的康辑。
- 測試計(jì)劃:劃定自動(dòng)化測試的范圍包含哪些需求摄欲,涉及到哪些測試過程
- 測試策略:確定自動(dòng)化測試的工具、編程方案晾捏、代碼管理蒿涎、測試重點(diǎn)
- 測試設(shè)計(jì):使用測試設(shè)計(jì)方法對被測試的需求進(jìn)行設(shè)計(jì)哀托,得出測試的測試點(diǎn)惦辛、用例思維導(dǎo)圖等
- 測試實(shí)施:根據(jù)測試設(shè)計(jì)進(jìn)行用例編寫,并且將測試用例用編程的方式實(shí)現(xiàn)測試腳本
- 測試執(zhí)行:執(zhí)行測試用例仓手,運(yùn)行測試腳本胖齐,生成測試結(jié)果
1.2 自動(dòng)化測試工具
基于Web UI
的自動(dòng)化測試工具主要有兩大類:付費(fèi)的商業(yè)版工具和免費(fèi)使用的開源版工具。典型的有兩種:
-
UFT嗽冒,QTP被惠普收購以后的新名稱呀伙。
- 通過程序的錄制,可以實(shí)現(xiàn)測試的編輯
- 錄制的測試腳本是 VBScript 語法
- 成熟版的商業(yè)付費(fèi)工具
- 工具比較龐大添坊,對具體的項(xiàng)目定制測試有難度
-
SELENIUM剿另,本次選擇的開源工具
- 本身不是測試工具,只是模擬瀏覽器操作的工具
- 背后有 Google 維護(hù)源代碼
- 支持全部主流的瀏覽器
- 支持主流的編程語言,包括:Java雨女、Python谚攒、C#、PHP氛堕、Ruby馏臭、JavaScript等
- 工具很小,可以實(shí)現(xiàn)對測試項(xiàng)目的定制測試方案
- 基于標(biāo)準(zhǔn)的 WebDriver 語法規(guī)范
Selenium 基本介紹
Selenium`是開源的自動(dòng)化測試工具讼稚,它主要是用于Web 應(yīng)用程序的自動(dòng)化測試括儒,不只局限于此,同時(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 主頁:https://github.com/SeleniumHQ/selenium
Selenium 是用于測試 Web 應(yīng)用程序用戶界面 (UI) 的常用框架帮寻。它是一款用于運(yùn)行端到端功能測試的超強(qiáng)工具。您可以使用多個(gè)編程語言編寫測試赠摇,并且 Selenium 能夠在一個(gè)或多個(gè)瀏覽器中執(zhí)行這些測試规婆。
Selenium 工具集
-
Selenium IDE
Selenium IDE (集成開發(fā)環(huán)境) 是一個(gè)創(chuàng)建測試腳本的原型工具。它是一個(gè) Firefox 插件蝉稳,實(shí)現(xiàn)簡單的瀏覽器操作的錄制與回放功能抒蚜,提供創(chuàng)建自動(dòng)化測試的建議接口。Selenium IDE 有一個(gè)記錄功能耘戚,能記錄用戶的操作嗡髓,并且能選擇多種語言把它們導(dǎo)出到一個(gè)可重用的腳本中用于后續(xù)執(zhí)行。
-
Selenium RC
Selenium RC 是selenium 家族的核心工具收津,Selenium RC 支持多種不同的語言編寫自動(dòng)化測試腳本饿这,通過selenium RC 的服務(wù)器作為代理服務(wù)器去訪問應(yīng)用從而達(dá)到測試的目的。
selenium RC 使用分Client Libraries 和Selenium Server撞秋。
- Client Libraries 庫主要主要用于編寫測試腳本长捧,用來控制selenium Server 的庫。
- Selenium Server 負(fù)責(zé)控制瀏覽器行為吻贿,總的來說串结,Selenium Server 主要包括3 個(gè)部分:Launcher、Http Proxy舅列、Core肌割。
-
Selenium Grid
Selenium Grid 使得 Selenium RC 解決方案能提升針對大型的測試套件或者哪些需要運(yùn)行在多環(huán)境的測試套件的處理能力。Selenium Grid 能讓你并行的運(yùn)行你的測試帐要,也就是說把敞,不同的測試可以同時(shí)跑在不同的遠(yuǎn)程機(jī)器上。這樣做有兩個(gè)優(yōu)勢榨惠,首先奋早,如果你有一個(gè)大型的測試套件盛霎,或者一個(gè)跑的很慢的測試套件,你可以使用 Selenium Grid 將你的測試套件劃分成幾份同時(shí)在幾個(gè)不同的機(jī)器上運(yùn)行耽装,這樣能顯著的提升它的性能摩渺。同時(shí),如果你必須在多環(huán)境中運(yùn)行你的測試套件剂邮,你可以獲得多個(gè)遠(yuǎn)程機(jī)器的支持摇幻,它們將同時(shí)運(yùn)行你的測試套件。在每種情況下挥萌,Selenium Grid 都能通過并行處理顯著地縮短你的測試套件的處理時(shí)間绰姻。
-
Selenium WebDriver
WebDriver 是 Selenium 2 主推的工具,事實(shí)上WebDriver是Selenium RC的替代品引瀑,因?yàn)镾elenium需要保留向下兼容性的原因狂芋,在 Selenium 2 中, Selenium RC才沒有被徹底的拋棄憨栽,如果使用Selenium開發(fā)一個(gè)新的自動(dòng)化測試項(xiàng)目帜矾,那么我們強(qiáng)烈推薦使用Selenium2 的 WebDriver進(jìn)行編碼。另外屑柔, 在Selenium 3 中屡萤,Selenium RC 被移除了。
自動(dòng)化編程語言Python選擇
- 測試人員的編程能力普遍不是很強(qiáng)掸宛,而Python作為一種腳本語言死陆,不僅功能強(qiáng)大,而且語法優(yōu)美唧瘾,支持多種自動(dòng)化測試工具措译,而且學(xué)習(xí)上手比較容易。
- 對于有一定編程基礎(chǔ)的人員饰序,使用Python作為自動(dòng)化測試的語言可以非常順暢的轉(zhuǎn)換领虹,幾乎沒有學(xué)習(xí)成本。同時(shí)Python是標(biāo)準(zhǔn)的面向?qū)ο蟮木幊陶Z言求豫,對于C#塌衰、Java等面向?qū)ο蟮恼Z言有著非常好的示例作用,通過Python的示例可以非常輕松的觸類旁通注祖,使用其他語言進(jìn)行Selenium2.0的WebDriver的使用猾蒂。
使用的工具集
- IDE: Jetbrains PyCharm
- 語言: Python
- 工具: Selenium WebDriver
- 源代碼管理: SVN/Git
JetBrains PyCharm 使用
- JetBrains PyCharm 的介紹
PyCharm 是 JetBrains 公司針對Python推出的IDE(Integrated Development Environment,集成開發(fā)環(huán)境)是晨。是目前最好的Python IDE之一。目前包含了兩個(gè)版本:
- 社區(qū)版舔箭,Community Edition
- 專業(yè)版罩缴,Professional Edition
- 付費(fèi)
- 比社區(qū)版主要多了Web開發(fā)框架
我們推薦使用免費(fèi)的社區(qū)版本蚊逢,進(jìn)行Python腳本的編寫和自動(dòng)化測試執(zhí)行。
PyCharm可以在官網(wǎng)下載箫章,http://www.jetbrains.com
Selenium 的環(huán)境搭建
在 Windows 搭建和部署 Selenium 工具
先安裝python
-
安裝 Selenium 工具包
由于 安裝好的 Python 默認(rèn)有
pip
Python 包管理工具烙荷,可以通過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 對于所有的瀏覽器都需要安裝驅(qū)動(dòng)桶至,本文以 Chrome 和 Firefox昼伴、IE為例設(shè)置瀏覽器和驅(qū)動(dòng)。
ChromeDriver下載地址:http://chromedriver.storage.googleapis.com/index.html
ChromeDriver 與 Chrome 對應(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 的對應(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)的配置**
- 首先圃郊,將下載好的對應(yīng)版本的瀏覽器安裝。
- 其次女蜈,在 Python 的根目錄中持舆,放入瀏覽器驅(qū)動(dòng)。
- 最好再重啟電腦伪窖,一般情況下不重啟也可以的逸寓。
?
1.3 Selenium 的最簡腳本
通過上一節(jié)的環(huán)境安裝成功以后,我們可以進(jìn)行第一個(gè)對Selenium 的使用覆山,就是最簡腳本編寫席覆。腳本如下:
# 聲明一個(gè)司機(jī),司機(jī)是個(gè)Chrome類的對象
driver = webdriver.Chrome()
# 讓司機(jī)加載一個(gè)網(wǎng)頁
driver.get("http://demo.xxx.com")
# 給司機(jī)3秒鐘去打開
sleep(3)
# 開始登錄
# 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 的最簡單的使用晦毙。這些代碼有開發(fā)基礎(chǔ)的同學(xué)生巡,一看都懂。
注意:Chrome 是 WebDriver 的子類见妒,是 WebDriver 類的一種
1.4 Selenium WebDriver API 的使用
通過上述最簡腳本的使用孤荣,我們可以來進(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)化測試的一個(gè)基本組成部分拘泞,我們可以將瀏覽器最大化,設(shè)置瀏覽器的高度和寬度以及對瀏覽器進(jìn)行導(dǎo)航操作等地来。
# 瀏覽器打開網(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提供了一系列的定位符以便使用元素定位方法幌蚊。常見的定位符有以下幾種:
- id
- name
- class name
- tag
- link text
- partial link text
- xpath
- css selector
那么我們以下的操作將會(huì)基于上述的定位符進(jìn)行定位操作谤碳。
對于元素的定位,WebDriver API可以通過定位簡單的元素和一組元素來操作溢豆。在這里蜒简,我們需要告訴Selenium如何去找元素,以至于他可以充分的模擬用戶行為漩仙,或者通過查看元素的屬性和狀態(tài)搓茬,以便我們執(zhí)行一系列的檢查。
在Selenium2中队他,WebDriver提供了多種多樣的find_element_by
方法在一個(gè)網(wǎng)頁里面查找元素卷仑。這些方法通過提供過濾標(biāo)準(zhǔn)來定位元素。當(dāng)然WebDriver也提供了同樣多種多樣的find_elements_by
的方式去定位多個(gè)元素漱挎。
盡管上述的方式系枪,可以進(jìn)行元素定位,實(shí)際上我們也是更多的用組合的方式進(jìn)行元素定位磕谅。
方法Method | 描述Description | 參數(shù)Argument | 示例Example |
---|---|---|---|
id |
該方法通過ID的屬性值去定位查找單個(gè)元素 | id: 需要被查找的元素的ID | find_element_by_id('search') |
name |
該方法通過name的屬性值去定位查找單個(gè)元素 | name: 需要被查找的元素的名稱 | find_element_by_name('q') |
class name |
該方法通過class的名稱值去定位查找單個(gè)元素 | class_name: 需要被查找的元素的類名 | find_element_by_class_name('input-text') |
tag_name |
該方法通過tag的名稱值去定位查找單個(gè)元素 | tag: 需要被查找的元素的標(biāo)簽名稱 | find_element_by_tag_name('input') |
link_text |
該方法通過鏈接文字去定位查找單個(gè)元素 | link_text: 需要被查找的元素的鏈接文字 | find_element_by_link_text('Log In') |
partial_link_text |
該方法通過部分鏈接文字去定位查找單個(gè)元素 | link_text: 需要被查找的元素的部分鏈接文字 | find_element_by_partial_link_text('Long') |
xpath |
該方法通過XPath的值去定位查找單個(gè)元素 | xpath: 需要被查找的元素的xpath | find_element_by_xpath('//*[@id="xx"]/a') |
css_selector |
該方法通過CSS選擇器去定位查找單個(gè)元素 | css_selector: 需要被查找的元素的ID | find_element_by_css_selector('#search') |
而find_elements_by
的方法依據(jù)匹配的具體標(biāo)準(zhǔn)返回一系列的元素私爷。
下面代碼通過ID的屬性值去定義一個(gè)查找文本框的查找:
<input id="search" type="text" name="q" value=""
class="input-text" maxlength="128" autocomplete="off"/>
根據(jù)上述代碼,這里我們使用find_element_by_id()
的方法去查找搜索框并且檢查它的最大長度maxlength
屬性膊夹。我們通過傳遞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í)上,通過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或一些爬蟲關(guān)于html節(jié)點(diǎn)查找的方法华坦。
依據(jù)XPath進(jìn)行查找
XPath是一種在XML文檔中搜索和定位節(jié)點(diǎn)node的一種查詢語言。所有的主流Web瀏覽器都支持XPath不从。
常用的XPath的方法有starts-with()
惜姐,contains()
和ends-with()
等
若想要了解更多關(guān)于XPath的內(nèi)容,請查看http://www.w3schools.com/XPath/
如下有一段HTML代碼消返,其中里面的<img>
沒有使用ID载弄,name或者類屬性耘拇,所以我們無法使用之前的方法撵颊。這里我們可以通過<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ì)師用來描繪HTML文檔的視覺的層疊樣式表妻熊。一般來說CSS用來定位多種多樣的風(fēng)格夸浅,同時(shí)可以用來是同樣的標(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>
我們來創(chuàng)建一個(gè)測試扔役,驗(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è)對象 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測試中治唤,有關(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")
# 對定位到的元素執(zhí)行鼠標(biāo)右鍵操作
ActionChains(driver).context_click(right).perform()
...
# 定位到要雙擊的元素
double = driver.find_element_by_xpath("xxx")
# 對定位到的元素執(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 單元測試框架
在上一節(jié),我們對 Selenium WebDriver 的使用榄檬,僅僅停留在讓網(wǎng)頁自動(dòng)的進(jìn)行操作的階段卜范,并沒有對任何一個(gè)步驟進(jìn)行“檢查”。當(dāng)然鹿榜,這樣沒有“檢查”的操作海雪,實(shí)際上是沒有測試意義的锦爵。那么第一項(xiàng),我們需要解決的便是“檢查”的問題奥裸。
所謂“檢查”险掀,實(shí)際上就是斷言。對需要檢查的步驟操作湾宙,通過對預(yù)先設(shè)置的期望值樟氢,和執(zhí)行結(jié)果的實(shí)際值之間的對比,得到測試的結(jié)果侠鳄。在這里埠啃,我們并不需要單獨(dú)的寫 if
語句進(jìn)行各種判定,而是可以使用編程語言中對應(yīng)的單元測試框架伟恶,即可解決好此類問題碴开。
目前 Java 語言主流的單元測試框架有 JUnit 和 TestNG。Python 語言主流的單元測試框架有 unittest 博秫。本小節(jié)的內(nèi)容潦牛,主要介紹 unittest 的使用,探討單元測試框架如何幫助自動(dòng)化測試台盯。
接下來我們將會(huì)使用 Python 語言的unittest
框架展開“檢查”罢绽。unittest
框架的原本的名字是PyUnit。是從JUnit 這樣一個(gè)被廣泛使用的經(jīng)典的Java應(yīng)用開發(fā)的單元測試框架創(chuàng)造而來静盅。類似的框架還有NUnit(.Net開發(fā)的單元測試框架)等良价。我們可以使用unittest框架為任意Python項(xiàng)目編寫可理解的單元測試集合。現(xiàn)在這個(gè)unittest已經(jīng)作為Python的標(biāo)準(zhǔn)庫模塊發(fā)布蒿叠。我們安裝完P(guān)ython以后明垢,便可以直接使用unittest。
使用unittest需要以下簡單的三步:
- 引入unittest模組
- 繼承unittest.TestCase基類
- 測試方法以
test
開頭
unittest 并未使用 Java 語言常見的注解方式市咽,依舊停留在 比較早期的 Java 版本中依靠方法名稱進(jìn)行識別的方式痊银。主要有以下兩個(gè)固定名字的方法:
- setUp():在每個(gè)測試方法運(yùn)行前,執(zhí)行施绎。是測試前置條件溯革。
- tearDown():在每個(gè)測試方法運(yùn)行后執(zhí)行,是測試清理操作谷醉。
具體的代碼如下:
## 引入unittest模組
import unittest
## 定義測試類致稀,名字為DemoTests
## 該類必須繼承unittest.TestCase基類
class DemoTests(unittest.TestCase):
## 使用'@'修飾符,注明該方法是類的方法
## setUpClass方法是在執(zhí)行測試之前需要先調(diào)用的方法
## 是開始測試前的初始化工作
@classmethod
def setUpClass(cls):
print("call setUpClass()")
## 每一個(gè)測試開始前的預(yù)置條件
def setUp(self):
print("call setUp()")
## 每一個(gè)測試結(jié)束以后的清理工作
def tearDown(self):
print("call tearDown()")
## 測試一(務(wù)必以test開頭)
def test_01(self):
print("call test_01()")
pass
## 測試三(務(wù)必以test開頭)
def test_02(self):
print("call test_02()")
pass
## 測試三(務(wù)必以test開頭)
def test_03(self):
print("call test_03()")
pass
## tearDownClass方法是執(zhí)行完所有測試后調(diào)用的方法
## 是測試結(jié)束后的清除工作
@classmethod
def tearDownClass(cls):
print("call tearDownClass()")
# 執(zhí)行測試主函數(shù)
if __name__ == '__main__':
## 執(zhí)行main全局方法俱尼,將會(huì)執(zhí)行上述所有以test開頭的測試方法
unittest.main(verbosity=2)
需要注意步驟:
- 引入 unittest 模組
- 繼承 unittest.TestCase 類
- 做測試用例的方法抖单,方法以 test_ 開頭
- 附加 setUp(), tearDown(), 在每個(gè) test_ 方法執(zhí)行前后 進(jìn)行執(zhí)行
- 附加 setUpClass(), tearDownClass()
需要在 類實(shí)例化的對象,運(yùn)行的開頭和結(jié)尾進(jìn)行執(zhí)行。
加了星號(*)的步驟矛绘,可以不用耍休。
上述代碼運(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
清晰的單元測試框架,提供 TestCase, TestSuite, TextTestRunner 等基本類
unittest 是 原生 Python 的一部分
unittest 有第三方可用的 HTML 庫货矮,可以輕松的生成 測試報(bào)告
-
unittest 的斷言配置使用
unittest 的斷言羊精,屬于
TestCase
類,只要繼承了該類次屠,均可以通過 self調(diào)用斷言方法 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
-
什么是封裝
封裝是一個(gè)面向?qū)ο缶幊痰母拍钊妇茫敲嫦驅(qū)ο缶幊痰暮诵膶傩运尴。ㄟ^將代碼內(nèi)部實(shí)現(xiàn)進(jìn)行密封和包裝,從而簡化編程赖捌。對Selenium進(jìn)行封裝的好處主要有如下三個(gè)方面:
- 使用成本低
- 不需要要求所有的測試工程師會(huì)熟練使用Selenium祝沸,而只需要會(huì)使用封裝以后的代碼
- 不需要對所有的測試工程師進(jìn)行完整培訓(xùn)。也避免工作交接的成本越庇。
- 測試人員使用統(tǒng)一的代碼庫
- 維護(hù)成本低
- 通過封裝罩锐,在代碼發(fā)生大范圍變化和遷移的時(shí)候,不需要維護(hù)所有代碼卤唉,只需要變更封裝的部分即可
- 維護(hù)代碼不需要有大量的工程師涩惑,只需要有核心的工程師進(jìn)行封裝的維護(hù)即可
- 代碼安全性
- 對作為第三方的Selenium進(jìn)行封裝,是代碼安全的基礎(chǔ)桑驱。
- 對于任何的代碼的安全隱患竭恬,必須由封裝來解決,使得風(fēng)險(xiǎn)可控熬的。
- 使用者并不知道封裝內(nèi)部的代碼結(jié)構(gòu)痊硕。
1.7 如何封裝
這里面向的用戶是開發(fā)者,有一定基礎(chǔ)的悦析,特別是面向?qū)ο箝_發(fā)基礎(chǔ)的開發(fā)者寿桨。封裝,最簡單直接就是函數(shù)、方法亭螟、類挡鞍。這里不再復(fù)述。
1.8 Page-Object設(shè)計(jì)模式介紹
-
Page-Object設(shè)計(jì)模式的本質(zhì)
Page Object設(shè)計(jì)模式是Selenium自動(dòng)化測試項(xiàng)目的最佳設(shè)計(jì)模式之一预烙,強(qiáng)調(diào)測試墨微、邏輯、數(shù)據(jù)和驅(qū)動(dòng)相互分離扁掸。
Page Object模式是Selenium中的一種測試設(shè)計(jì)模式翘县,主要是將每一個(gè)頁面設(shè)計(jì)為一個(gè)Class,其中包含頁面中需要測試的元素(按鈕谴分,輸入框锈麸,標(biāo)題等),這樣在Selenium測試頁面中可以通過調(diào)用頁面類來獲取頁面元素牺蹄,這樣巧妙的避免了當(dāng)頁面元素id或者位置變化時(shí)忘伞,需要改測試頁面代碼的情況。當(dāng)頁面元素id變化時(shí)沙兰,只需要更改測試頁Class中頁面的屬性即可氓奈。
它的好處如下:
- 集中管理元素對象,便于應(yīng)對元素的變化
- 集中管理一個(gè)page內(nèi)的公共方法鼎天,便于測試用例的編寫
- 后期維護(hù)方便舀奶,不需要重復(fù)的復(fù)制和修改代碼
具體的做法如下:
- 創(chuàng)建一個(gè)頁面的類
- 在類的構(gòu)造方法中,傳遞 WebDriver 參數(shù)斋射。
- 在測試用例的類中育勺,實(shí)例化頁面的類,并且傳遞在測試用例中已經(jīng)實(shí)例化的WebDriver對象绩鸣。
- 在頁面的類中怀大,編寫該頁面的所有操作的方法
- 在測試用例的類中,調(diào)用這些方法
-
Page 如何劃分
一般通過繼承的方式呀闻,進(jìn)行按照實(shí)際Web頁面進(jìn)行劃分
-
Page-Object 類如何實(shí)現(xiàn)
實(shí)現(xiàn)的示例
-
Page 基類
- 設(shè)計(jì)了一個(gè)基本的 Page類化借,以便所有的頁面進(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):
"""
打開頁面
:param url:
:return:
"""
self.base_driver.navigate(url)
self.base_driver.maximize_window()
sleep(2)
```
- 所有子類(頁面)都具有的業(yè)務(wù)功能
- select\_app
- logout
- Sub Pages(s)子類
- 具體的頁面的類,定義了某個(gè)具體的頁面的功能
- 必須繼承基類
```
class MainPage(BasePage):
```
- 特定頁面的業(yè)務(wù)
- 使用基類的 `self.base_driver` 成員變量
- Tests 類
- 這部分描述的是具體的測試用例科贬。
- 聲明全局變量
```
base_driver = None
base_url = None
main_page = None
```
- 調(diào)用各種頁面(pages)
- 實(shí)例化Page
```python
self.main_page = MainPage(self.base_driver)
```
- 使用page的對象泳梆,調(diào)用成員方法
```python
self.main_page.open(self.base_url)
self.main_page.change_language(lang)
```
2. 構(gòu)建測試方案
2.1 數(shù)據(jù)驅(qū)動(dòng)在自動(dòng)化測試中的應(yīng)用
-
什么是數(shù)據(jù)驅(qū)動(dòng)
主要的數(shù)據(jù)驅(qū)動(dòng)方式有兩種:
- 通過 文本文件或者 Excel 文件存儲(chǔ)數(shù)據(jù)鳖悠,并通過程序讀取數(shù)據(jù),遍歷所有的行
- 通過數(shù)據(jù)庫存儲(chǔ)數(shù)據(jù)优妙,并通過程序和 SQL 腳本讀取數(shù)據(jù)乘综,遍歷所有的行
通過 CSV 文件 或者 MySQL 數(shù)據(jù)庫,是主流的數(shù)據(jù)驅(qū)動(dòng)方式套硼。當(dāng)然數(shù)據(jù)驅(qū)動(dòng)也可以結(jié)合單元測試框架的參數(shù)化測試進(jìn)行編寫(此部分本文不做具體描述)卡辰。
無論使用了 哪一種(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)行測試
# 使用字典類型
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)行測試
# 使用字典類型
data_to_test = {
"key1": row[0],
"key2": row[1]
}
cur.close()
connect.close()
```
-
需要掌握的知識點(diǎn):
- python的字典類型
dict
類型 - python的讀寫文件
- python的讀寫數(shù)據(jù)庫
- for循環(huán)
- 注意資源的釋放
- 關(guān)閉數(shù)據(jù)庫游標(biāo)和連接
- 關(guān)閉文件
- python的字典類型
2.2 測試方案的編碼實(shí)現(xiàn)
- main.py 測試入口
- runner.py 測試運(yùn)行器
- cases 測試用例
- pages 測試頁面
- base 底層封裝與驅(qū)動(dòng)
2.3 測試報(bào)告的生成
如何生成測試報(bào)告
測試報(bào)告的種類
-
HTML 測試報(bào)告的生成
HTML測試報(bào)告需要引入HTMLTestRunner
HTMLTestRunner是基于Python2.7的九妈,我們的課程講義基于Python3.x,那么需要對這個(gè)文件做一定的修改雾鬼。
測試的示例代碼如下
```python
# 聲明一個(gè)測試套件
suite = unittest.TestSuite()
# 添加測試用例到測試套件
suite.addTest(RanzhiTests("test_ranzhi_login"))
# 創(chuàng)建一個(gè)新的測試結(jié)果文件
buf = open("./result.html", "wb")
# 聲明測試運(yùn)行的對象
runner = HTMLTestRunner.HTMLTestRunner(stream=buf,
title="Ranzhi Test Result",
description="Test Case Run Result")
# 運(yùn)行測試萌朱,并且將結(jié)果生成為HTML
runner.run(suite)
# 關(guān)閉文件輸出
buf.close()
```