WebDriver基礎(chǔ)
歡迎閱讀WebDriver基礎(chǔ)講義。本篇講義將會(huì)重點(diǎn)介紹Selenium WebDriver的環(huán)境搭建和基本使用方法。
WebDriver環(huán)境搭建
Selenium WebDriver 又稱為 Selenium2。
Selenium 1 + WebDriver = Selenium 2
WebDriver是主流Web應(yīng)用自動(dòng)化測(cè)試框架,具有清晰面向?qū)ο?API,能以最佳的方式與瀏覽器進(jìn)行交互。
支持的瀏覽器:
- Mozilla Firefox
- Google Chrome
- Microsoft Internet Explorer
- Opera
- Safari
- Apple iPhone
- Android browsers
環(huán)境搭建步驟
在上一篇中,我們已經(jīng)確認(rèn)使用Python來(lái)進(jìn)行WebDriver的編碼和操作。事實(shí)上Python+Selenium WebDriver環(huán)境的搭建分為兩個(gè)部分:
- 安裝python
- 安裝Selenium
標(biāo)準(zhǔn)的安裝步驟
-
選擇Python的版本。
Python主流的有兩個(gè)大的版本,2.7和3.5(請(qǐng)注意,從Python的3.5版本開(kāi)始,不再支持Windows XP操作系統(tǒng),Windows XP用戶請(qǐng)安裝3.4版本)。我們的例子將會(huì)選用面向未來(lái)的3.5版本。
-
安裝Python。
在Python的官網(wǎng)下載最新的安裝包,進(jìn)行界面安裝。https://www.python.org/
安裝的時(shí)候,推薦選擇“Add exe to path”,將會(huì)自動(dòng)添加Python的程序到環(huán)境變量中。然后可以在命令行輸入
python -V
檢測(cè)安裝的Python版本。當(dāng)前的版本安裝中將會(huì)默認(rèn)已經(jīng)安裝了
setuptools
和pip
這兩個(gè)Python的基本工具。如果使用了比較舊的Python版本的話,需要自行安裝這兩個(gè)工具。- setuptools:Python的基礎(chǔ)工具包,用來(lái)構(gòu)建、安裝卸載Python程序
- pip:Python軟件包的安裝和管理工具。通過(guò)pip可以簡(jiǎn)單的安裝Python的任意類庫(kù)
-
安裝Selenium2.0版本。
在Windows安裝Selenium2.0,有兩種途徑。使用pip命令行或者源碼安裝。以下兩種方法,使用任何一個(gè)均可。推薦pip的方式。
-
方法一:pip命令行安裝,運(yùn)行 | cmd,打開(kāi)命令行,
-U
其實(shí)就是--upgrade
,升級(jí)安裝。pip install -U selenium
-
方法二:源碼解壓安裝,前往https://pypi.python.org/pypi/selenium下載最新版的PyPI版本的Selenium,解壓后執(zhí)行
python setup.py install
?
-
Ubuntu下的環(huán)境搭建
在Ubuntu下的Python的解釋器一般情況下已經(jīng)存在了。我們需要打開(kāi)終端,輸入python -V
命令進(jìn)行驗(yàn)證。如果沒(méi)有安裝Python,那么需要去Python官網(wǎng)上下載指定版本的源文件,進(jìn)行源碼安裝。安裝完了以后并進(jìn)行環(huán)境變量的設(shè)置。
安裝Selenium WebDriver的方法與上述在Windows環(huán)境下安裝部署的方法一致。依舊推薦使用pip命令行進(jìn)行安裝。
使用IDE編寫(xiě)Python
在上述環(huán)境搭建好以后,我們便可使用Python來(lái)編寫(xiě)自動(dòng)化腳本程序,執(zhí)行Selenium自動(dòng)化測(cè)試。在此之前,我們依舊需要解決一個(gè)問(wèn)題,那就是IDE的選擇。
IDE,Integrated Development Environment,集成開(kāi)發(fā)環(huán)境。一個(gè)好的編輯器或者好的IDE將會(huì)極大的提高生產(chǎn)力,幫我們做很多事情,使得編碼工作更加簡(jiǎn)單,編碼的體驗(yàn)更加容易。一般情況下,我們有以下幾種工具可以選擇:
- IDLE:Python自帶的IDE,功能簡(jiǎn)單,使用方便
- Notepad++:一個(gè)強(qiáng)大的開(kāi)源編輯器
- Vim:Linux系統(tǒng)中最好用的編輯器之一
- Sublime Text:一個(gè)非常輕便好用的現(xiàn)代化的編輯器,推薦。
- PyCharm:JetBrains公司提供的現(xiàn)代化的跨平臺(tái)的Python IDE。
使用Sublime Text 3搭建Python環(huán)境
-
****通過(guò)快捷鍵
Ctrl
+ 或者View > Show Console打開(kāi)控制臺(tái),輸入以下代碼并回車import urllib.request,os; pf = 'Package Control.sublime-package'; ipp = sublime.installed_packages_path(); urllib.request.install_opener( urllib.request.build_opener( urllib.request.ProxyHandler()) ); open(os.path.join(ipp, pf), 'wb').write(urllib.request.urlopen( 'http://sublime.wbond.net/' + pf.replace(' ','%20')).read())
安裝完以后,重啟Sublime Text 3
如果在Perferences->package settings中看到package control這一項(xiàng),則安裝成功
按下Ctrl+Shift+P調(diào)出命令面板
輸入install package選項(xiàng)并回車
輸入i,匹配到以后,按回車,安裝。Anaconda是一個(gè)終極的Python插件。安裝完了以后便可用Sublime Text 3編寫(xiě)Python代碼,并且使用
Ctrl
+B
來(lái)編譯執(zhí)行。
一般來(lái)說(shuō),一個(gè)好的IDE提供一下功能,使你的編碼開(kāi)發(fā)工作變得更有效率:
- 一個(gè)圖形化的智能代碼提示和補(bǔ)全功能
- 可以輕松查看方法和類
- 語(yǔ)法高亮
- 提供單元測(cè)試和調(diào)試的工具
- 源代碼版本管理工具的支持
我們可以嘗試用上述的編輯器或者IDE來(lái)進(jìn)行Python代碼編寫(xiě)工作。
開(kāi)始使用WebDriver
接下來(lái)我們嘗試幾個(gè)簡(jiǎn)單的例子來(lái)體會(huì)一下Selenium WebDriver的使用。
示例1
## 引入WebDriver的包
from selenium import webdriver
## 創(chuàng)建瀏覽器對(duì)象
browser = webdriver.Firefox()
## 打開(kāi)百度網(wǎng)站
browser.get('https://www.baidu.com/')
示例2
## 引入WebDriver包
from selenium import webdriver
## 引入WebDriver Keys包
from selenium.webdriver.common.keys import Keys
## 創(chuàng)建瀏覽器對(duì)象
browser = webdriver.Firefox()
## 導(dǎo)航到百度主頁(yè)
browser.get('https://www.baidu.com')
## 檢查標(biāo)題是否為‘百度一下,你就知道’
assert '百度一下,你就知道' in browser.title
## 找到名字為wd的元素,賦值給elem
elem = browser.find_element_by_name('wd') # 找到搜索框
elem.send_keys('seleniumhq' + Keys.RETURN) # 搜索seleniumhq
## 關(guān)閉瀏覽器
browser.quit()
Selenium 3.0.1 出現(xiàn)的問(wèn)題以及解決
3.0.1 更新以后,需要做兩個(gè)操作:
- Geckodriver executable needs to be in PATH。Geckodirver的下載地址:https://github.com/mozilla/geckodriver/releases
報(bào)錯(cuò)內(nèi)容:
WebDriverException:Message:'geckodriver'executable needs to be in Path
geckodriver是一原生態(tài)的第三方瀏覽器,對(duì)于selenium3.x版本都會(huì)使用geckodriver來(lái)驅(qū)動(dòng)firefox,所以需要下載geckodriver.exe。放置在Path 環(huán)境變量可以訪問(wèn)到的地方。例如 C:\python34
- 需要將火狐的安裝路徑放到path,然后重啟(必須重啟電腦)
報(bào)錯(cuò)內(nèi)容:
selenium.common.exceptions.WebDriverException: Message: 'geckodriver' executable needs to be in PATH.
XAMPP的安裝部署和環(huán)境搭建
XAMPP的安裝,在Windows操作系統(tǒng)中比較簡(jiǎn)單,可以直接運(yùn)行安裝文件,默認(rèn)全部下一步,即可完成軟件的安裝。
請(qǐng)注意:Windows XP系統(tǒng)只能可以 XAMPP 1.8.2
版本;Windows 7以及以上的系統(tǒng)可以安裝最新版的XAMPP。XAMPP不分32位和64位操作系統(tǒng)。
XAMPP的部署
XAMPP = OS + Apache + MySQL + PHP + Perl
我們一般部署的網(wǎng)站,符合XAMPP環(huán)境的話,只需要啟動(dòng)Apache和MySQL兩個(gè)應(yīng)用。
部署步驟
啟動(dòng)Apache
啟動(dòng)MySQL
解壓網(wǎng)站源文件,例如解壓然之:ranzhi.2.5.zip,請(qǐng)把壓縮包里面的
ranzhi
這個(gè)文件夾解壓出來(lái);禪道也類似,需要把壓縮包中的zentaopms
文件夾解壓出來(lái)部署源文件,請(qǐng)將解壓以后的源文件放到
xampp\htdocs
文件夾中-
通過(guò)瀏覽器訪問(wèn)部署好的網(wǎng)站源文件,進(jìn)行向?qū)О惭b。
http://localhost/ranzhi/www
PS
:這里我們主要支持的是PHP
+MySQL
開(kāi)發(fā)的網(wǎng)站部署。
XAMPP的問(wèn)題解決
- 無(wú)法啟動(dòng)Apache:請(qǐng)認(rèn)真查看日志,判斷80和443端口被什么樣的程序占用,需要關(guān)閉對(duì)應(yīng)程序,或者修改Apache的端口。
-
IIS
:控制面板 | 管理工具 | Internet信息服務(wù) | 默認(rèn)網(wǎng)站 | 關(guān)閉 -
VisualSVN Server
: 控制面板 | 管理工具 | VisualSVN Server | 關(guān)閉 -
VMware Workstation
: 開(kāi)始 | VMware Workstation | 編輯 | 首選項(xiàng) | 共享虛擬機(jī) | 禁用共享 -
HP LoadRunner
: 右側(cè)任務(wù)欄 | 右鍵 | 關(guān)閉 -
修改XAMPP Apache 端口
:Config | httpd.conf修改Linsten 80 | Httpd-ssl.conf修改 Listen 443
- 無(wú)法啟動(dòng)MySQL:請(qǐng)認(rèn)真查看錯(cuò)誤日志,找到已經(jīng)啟動(dòng)的MySQL的程序進(jìn)程,殺掉該進(jìn)程。
使用unittest編寫(xiě)測(cè)試腳本
通過(guò)上面的例子,我們可以簡(jiǎn)單的寫(xiě)出Selenium WebDriver的腳本,但是對(duì)于測(cè)試工作來(lái)說(shuō),上述的腳本還遠(yuǎn)遠(yuǎn)不夠。因?yàn)樯鲜龅哪_本沒(méi)有“檢查”。
接下來(lái)我們將會(huì)使用Python語(yǔ)言的unittest
框架展開(kāi)“檢查”。
unittest基礎(chǔ)
unittest
框架的原本的名字是PyUnit。是從JUnit這樣一個(gè)被廣泛使用的Java應(yīng)用開(kāi)發(fā)的單元測(cè)試框架創(chuàng)造而來(lái)。類似的框架還有NUnit(.Net開(kāi)發(fā)的單元測(cè)試框架)等。
我們可以使用unittest框架為任意Python項(xiàng)目編寫(xiě)可理解的單元測(cè)試集合。現(xiàn)在這個(gè)unittest已經(jīng)作為Python的標(biāo)準(zhǔn)庫(kù)模塊發(fā)布。我們安裝完P(guān)ython以后,便可以直接使用unittest。
unittest框架提供了編寫(xiě)test cases
,test suites
和test fixtures
的基本功能。我們首先關(guān)注 Test cases
的編寫(xiě)與執(zhí)行。
使用unittest需要以下簡(jiǎn)單的三步:
- 引入unittest模組
- 繼承unittest.TestCase基類
- 測(cè)試方法以
test
開(kāi)頭
unittest示例
## 引入unittest模組
import unittest
## 定義測(cè)試類,名字為DemoTests
## 該類必須繼承unittest.TestCase基類
class DemoTests(unittest.TestCase):
## 使用'@'修飾符,注明該方法是類的方法
## setUpClass方法是在執(zhí)行測(cè)試之前需要先調(diào)用的方法
## 是開(kāi)始測(cè)試前的初始化工作
@classmethod
def setUpClass(cls):
pass
## 測(cè)試一(務(wù)必以test開(kāi)頭)
def test_01(self):
pass
## 測(cè)試三(務(wù)必以test開(kāi)頭)
def test_02(self):
pass
## 測(cè)試三(務(wù)必以test開(kāi)頭)
def test_03(self):
pass
## tearDownClass方法是執(zhí)行完所有測(cè)試后調(diào)用的方法
## 是測(cè)試結(jié)束后的清除工作
@classmethod
def tearDownClass(cls):
pass
# 執(zhí)行測(cè)試主函數(shù)
if __name__ == '__main__':
## 執(zhí)行main全局方法,將會(huì)執(zhí)行上述所有以test開(kāi)頭的測(cè)試方法
unittest.main(verbosity=2)
Python知識(shí)的補(bǔ)充:
- Python文件的后綴名是
.py
-
.py
文件可以用來(lái)直接執(zhí)行。也可以被用來(lái)作為模塊導(dǎo)入。在cmd命令行中執(zhí)行的命令為python demo.py
- 在Python中導(dǎo)入模塊(模組)一般使用的是
import
使用unittest框架編寫(xiě)Selenium WebDriver測(cè)試
接下來(lái)我們查看一個(gè)完整的Selenium WebDriver自動(dòng)化測(cè)試實(shí)例
實(shí)例
import unittest
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
class SearchTests(unittest.TestCase):
def setUp(self):
# 創(chuàng)建一個(gè)新的瀏覽器對(duì)象
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(30)
self.driver.maximize_window()
# 導(dǎo)航到京東主頁(yè)
self.driver.get("https://www.jd.com/")
def test_search_by_category(self):
# 獲取到搜索框
self.search_field = self.driver.find_element_by_id("key")
self.search_field.clear()
# 輸入iphone 6s plus并按下回車進(jìn)行搜索
self.search_field.send_keys("iphone 6s plus" + Keys.RETURN)
# 獲取所有的查詢結(jié)果
products = self.driver.find_elements_by_css_selector("li[class='gl-item']")
# 斷言:檢查查詢出來(lái)的個(gè)數(shù)是否為24個(gè)
self.assertEqual(24, len(products))
def tearDown(self):
# 關(guān)閉瀏覽器對(duì)象
self.driver.quit()
if __name__ == '__main__':
unittest.main(verbosity=2)
理解unittest框架提供的各種斷言方法
方法 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)解釋失敗的原因 |
WebDriver API 基本操作
這里我們將會(huì)開(kāi)始WebDriver API的基本操作,從元素定位以及瀏覽器的基本操作開(kāi)始。
定位符
元素的定位和操作是自動(dòng)化測(cè)試的核心部分,其操作是建立在定位的基礎(chǔ)上的。因此我們首選要開(kāi)始定位元素。
在html里面,元素具有各種各樣的屬性。我們可以通過(guò)這樣唯一區(qū)別其他元素的屬性來(lái)定位到這個(gè)元素。WebDriver提供了一系列的元素定位方法。常見(jiàn)的有以下幾種:
- id
- name
- class name
- tag
- link text
- partial link text
- xpath
- css selector
查找簡(jiǎn)單元素
我們從簡(jiǎn)單的一個(gè)元素開(kāi)始定位。最基本的方法是id
和name
。大多數(shù)元素有這兩個(gè)屬性,在對(duì)控件的id
和name
命名是一般也會(huì)使其有意義,而取不同的名字。
例如我們看下面這段html
<input id="search" type="text" name="q" value="" class="input-text" maxlength="128" />
我們可以使用對(duì)應(yīng)的方法來(lái)定位這個(gè)input
find_element_by_id('search')
find_element_by_name('q')
find_element_by_class_name('input-text')
這里我們開(kāi)始用最簡(jiǎn)單的方式來(lái)嘗試定位
查看下面一個(gè)例子
self.driver.get('http://pro.demo.zentao.net')
# 用name定位用戶文本輸入框
self.account_field = self.driver.find_element_by_name('account')
# 用name定位密碼文本輸入框
self.password_field = self.driver.find_element_by_name('password')
self.account_field.clear()
self.password_field.clear()
self.driver.implicitly_wait(30)
# 輸入用戶名demo
self.account_field.send_keys('demo')
# 輸入密碼123456
self.password_field.send_keys('123456')
self.driver.find_element_by_id('submit').click()
self.driver.implicitly_wait(30)
companyname = self.driver.find_element_by_id('companyname')
self.assertEqual('demo項(xiàng)目管理系統(tǒng)', companyname.text)
示例2
self.driver.find_element_by_id('menuproduct').click()
self.driver.implicitly_wait(30)
self.driver.find_element_by_id('menuproject').click()
self.driver.implicitly_wait(30)
self.driver.find_element_by_id('menuqa').click()
self.driver.implicitly_wait(30)
self.driver.find_element_by_id('menudoc').click()
self.driver.implicitly_wait(30)
self.driver.find_element_by_id('menureport').click()
self.driver.implicitly_wait(30)
self.driver.find_element_by_id('menucompany').click()
self.driver.implicitly_wait(30)
self.driver.find_element_by_link_text('退出').click()
self.driver.implicitly_wait(30)
此外XPath
定位和CSS Selector
定位,和定位一組元素這樣的內(nèi)容案例,將在后續(xù)的講義繼續(xù)探討和講解。
控制瀏覽器
瀏覽器的控制也是自動(dòng)化測(cè)試的一個(gè)基本組成部分,我們可以將瀏覽器最大化,設(shè)置瀏覽器的高度和寬度以及對(duì)瀏覽器進(jìn)行導(dǎo)航操作等。
## 瀏覽器最大化
driver.maximize_window()
## 設(shè)置瀏覽器的高度為800像素,寬度為480像素
driver.set_window_size(480, 800)
## 瀏覽器后退
driver.back()
## 瀏覽器前進(jìn)
driver.forward()
這里我們做一個(gè)綜合性的練習(xí)實(shí)例
# coding=utf-8
import unittest
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
# import sys
# reload(sys)
# sys.setdefaultencoding('utf8')
class WebDriverTests(unittest.TestCase):
@classmethod
def setUpClass(cls):
# create a new Firefox session
cls.driver = webdriver.Firefox()
cls.driver.get('about:blank')
cls.driver.implicitly_wait(30)
print(" -- set up finished -- ")
print()
def test_01_navigate(self):
pass
url_baidu = 'https://www.baidu.com/'
url_zentao = 'http://pro.demo.zentao.net/user-login-Lw==.html'
# 導(dǎo)航到百度
self.driver.get(url_baidu)
self.driver.maximize_window()
self.driver.implicitly_wait(30)
# 導(dǎo)航到禪道
self.driver.get(url_zentao)
self.driver.maximize_window()
self.driver.implicitly_wait(30)
# 后退
self.driver.back()
self.assertEqual(url_baidu, self.driver.current_url)
self.driver.implicitly_wait(30)
# 前進(jìn)
self.driver.forward()
self.assertEqual(url_zentao, self.driver.current_url)
self.driver.implicitly_wait(30)
print("-- test 01 finished -- ")
print()
def test_02_element_interaction(self):
self.driver.get('http://pro.demo.zentao.net')
## 找到用戶名和密碼的輸入框
self.account_field = self.driver.find_element_by_name('account')
self.password_field = self.driver.find_element_by_name('password')
## 清除當(dāng)前的輸入
self.account_field.clear()
self.password_field.clear()
self.driver.implicitly_wait(30)
## 輸入用戶名和密碼,進(jìn)行登錄
self.account_field.send_keys('demo')
self.password_field.send_keys('123456')
self.driver.find_element_by_id('submit').click()
self.driver.implicitly_wait(30)
companyname = self.driver.find_element_by_id('companyname')
self.assertEqual('demo項(xiàng)目管理系統(tǒng)', companyname.text)
print(companyname.get_attribute('type'))
print()
self.driver.implicitly_wait(30)
print('-- test 02 finished -- ')
print()
def test_03_element_interation2(self):
## 這里執(zhí)行了一段JavaScript代碼
js = 'selectTheme("green")'
self.driver.execute_script(js)
self.driver.implicitly_wait(30)
js = 'selectTheme("red")'
self.driver.execute_script(js)
self.driver.implicitly_wait(30)
js = 'selectTheme("lightblue")'
self.driver.execute_script(js)
self.driver.implicitly_wait(30)
js = 'selectTheme("blackberry")'
self.driver.execute_script(js)
self.driver.implicitly_wait(30)
self.driver.find_element_by_id('menuproduct').click()
self.driver.implicitly_wait(30)
self.driver.find_element_by_id('menuproject').click()
self.driver.implicitly_wait(30)
self.driver.find_element_by_id('menuqa').click()
self.driver.implicitly_wait(30)
self.driver.find_element_by_id('menudoc').click()
self.driver.implicitly_wait(30)
self.driver.find_element_by_id('menureport').click()
self.driver.implicitly_wait(30)
self.driver.find_element_by_id('menucompany').click()
self.driver.implicitly_wait(30)
self.driver.find_element_by_link_text('退出').click()
self.driver.implicitly_wait(30)
WebDriverWait(self.driver, 10).until(
expected_conditions.element_to_be_clickable((By.ID, "submit")))
self.driver.implicitly_wait(30)
print('-- test 03 finished -- ')
print()
def test_04_cookies(self):
self.driver.add_cookie(
{'name': 'key-neeeeew', 'value': 'value-neeeewwwww'})
# 遍歷cookies 中的name 和value 信息打印,當(dāng)然還有上面添加的信息
for cookie in self.driver.get_cookies():
print("%s -> %s" % (cookie['name'], cookie['value']))
print()
self.driver.delete_all_cookies()
cookies = self.driver.get_cookies()
print(cookies)
print()
print('-- test 04 finished -- ')
print()
@classmethod
def tearDownClass(cls):
# close the browser window
cls.driver.quit()
pass
print('-- tear down finished -- ')
print()
if __name__ == '__main__':
unittest.main(verbosity=2)