JB的閱讀之旅-Selenium2自動化測試實戰

jb發表於2018-10-22

現狀

好久好久沒有更新部落格了,應該有一個月了吧,這段時間內,好忙,公司的業務在上漲期,但是卻把下面的一個小朋友砍掉了(換組),所以很多打雜的時候都讓jb去做了,基本上每天活著跟鹹魚一樣~

JB的閱讀之旅-Selenium2自動化測試實戰

雖然是鹹魚,但是還是要學習,最近在返璞歸真,做了那麼多年的測試狗,還是要學習點理論知識,畢竟得有些料才能吹的更愉快;

JB的閱讀之旅-Selenium2自動化測試實戰

這段時間基本上都是在學習測試相關的書籍,測試工作,理論知識等,也看到不同的測試書籍,感覺很多都很差強人意,每本書都總覺得有所欠缺,如果有機會,挺想自己擼一本的,哈哈哈;

JB的閱讀之旅-Selenium2自動化測試實戰

本篇作為閱讀篇的第一篇,主要來介紹下selenium,介紹的原因是,最近有些專案是web端的,隨著專案的穩定,後面會考慮自動化,而PC的自動化,基本上都是用selenium,那就來圍觀吧~

JB的閱讀之旅-Selenium2自動化測試實戰

前言

之前看coder-pig文章時有大致瞭解,很早之前也聽過selenium,但是還是想系統看一遍,聽說蟲師的這本書還可以,因此就來學習學習下~

雖然這部書叫selenium,但是有大致三分之二的內容是測試跟Python相關的內容,因此會優先介紹selenium相關內容,最後會貼一些自己覺得有點用的資訊;

說明,本篇內容是基於coder-pig的原文進行補充及介紹,算是一個整理;

書籍資訊

本書全名:Selenium 2 自動化測試實戰,基於Python語言 作者:蟲師 出版社:電子工業出版社 版次:2016年1月第1版

Selenium

簡介

Selenium是一個自動化測試框架,通過他,可以編寫程式碼讓瀏覽器:

  • 自動載入網頁,獲取當前呈現頁面的原始碼;
  • 模擬點選和其他互動方式,最常用:模擬表單提交(比如模擬登入);
  • 頁面截圖;
  • 判斷網頁某些動作是否發生,等等。

Selenium是不支援瀏覽器功能的,需要和第三方的瀏覽器一起搭配使用,支援下述瀏覽器,你需要把對應的瀏覽器驅動下載到Python的對應路徑下:

安裝

直接利用pip命令進行安裝,命令如下:

pip install selenium
複製程式碼

接著下載瀏覽器驅動,大部分用的Chrome瀏覽器,就以此為例,其他瀏覽器可自行搜尋相關文件,開啟Chrome瀏覽器鍵入:

chrome://version
複製程式碼

即可檢視Chrome瀏覽器版本的相關資訊,主要是關注版本號:

Google Chrome	68.0.3440.106 (正式版本) (32 位) (cohort: Stable)
修訂版本	1c32c539ce0065a41cb79da7bfcd2c71af1afe62-refs/branch-heads/3440@{#794}
作業系統	Windows
JavaScript	V8 6.8.275.26
Flash	30.0.0.154 C:\Users\jb\AppData\Local\Google\Chrome\User Data\
PepperFlash\30.0.0.154\pepflashplayer.dll
使用者代理	Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, 
like Gecko) Chrome/68.0.3440.106 Safari/537.36
命令列	"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" 
--flag-switches-begin --flag-switches-end
可執行檔案路徑	C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
個人資料路徑	C:\Users\jb\AppData\Local\Google\Chrome\User Data\Default
複製程式碼

這裡看到,大版本號是68,接下來到下面的這個網站檢視對應的驅動版本號:

https://chromedriver.storage.googleapis.com/2.41/notes.txt
複製程式碼

可以看到如下的版本號資訊。

----------ChromeDriver v2.41 (2018-07-27)----------
Supports Chrome v67-69
Resolved issue 2458: Chromedriver fails to start with whitelisted-ips option [[Pri-1]]
Resolved issue 2379: Returned capabilities should include remote debugging port [[Pri-2]]
Resolved issue 1005: driver.manage().window().getSize() is not implemented on Android [[Pri-2]]
Resolved issue 2474: desktop launcher error messages are not readable by users [[Pri-]]
Resolved issue 2496: Fail fast when not able to start binary [[Pri-]]
Resolved issue 1990: Close Window return value does not conform with spec [[Pri-]]
複製程式碼

ok,那就是下載2.4.1這個版本驅動,連結:

https://chromedriver.storage.googleapis.com/index.html?path=2.41/ 
複製程式碼

開啟後可以看到所示的頁面,選擇對應的系統下載即可。

JB的閱讀之旅-Selenium2自動化測試實戰

下載完成後,把zip檔案解壓下,解壓後的chromedriver.exe拷貝到Python的Scripts目錄下,另外這裡不用糾結win32,在64位的瀏覽器上也是可以正常使用的!Mac的話把解壓後的檔案拷貝到usr/local/bin目錄下 ,Ubuntu的話則拷貝到usr/bin目錄下。

demo

接下來,來個小demo吧:

# coding = utf-8
# 為了防止亂碼問題,以及方便的在程式中新增中文註釋,把編碼統一成 UTF-8。
from selenium import webdriver
# 匯入 selenium 的 webdriver 包,只有匯入 webdriver 包我們才能使用 webdriver API 進行自動化指令碼的開發。
browser = webdriver.Chrome()
#把webdriver的Chrome物件賦值給變數driver;
#只有獲得了瀏覽器物件後,才可以啟動瀏覽器,開啟網址,操作頁面元素,Chrome瀏覽器驅動預設已經在Selenium WebDriver包裡了,可以直接呼叫;
#要先安裝相關的瀏覽器驅動
browser.get("http://www.baidu.com")
#獲得瀏覽器物件後,通過 get()方法,可以向瀏覽器傳送網址。
html_text = browser.page_source  
# 獲得頁面程式碼
browser.quit()
#退出並關閉視窗
複製程式碼

執行這段程式碼後,會自動調起Chrome瀏覽器,並訪問百度,可以看到瀏覽器頂部有下面的提示。

JB的閱讀之旅-Selenium2自動化測試實戰

並且控制檯會輸出HTML的程式碼,和Chrome的Elements頁面結構完全一致。 那就可以用selenium這麼玩了;

JB的閱讀之旅-Selenium2自動化測試實戰

不過,在實踐之前,再繼續介紹下selenium其他方法吧;

API

定位元素

  • find_element_by_id():根據id定位
  • find_element_by_name():根據節點名定位
  • find_element_by_class_name():根據class定位
  • find_element_by_tag_name():通過tag定位
  • find_element_by_link_text():根據連結的文字來定位
  • find_element_by_partial_link_text():根據元素標籤對之間的部分文字資訊來定位
  • find_element_by_xpath():使用Xpath進行定位
  • find_element_by_css_selector():根據css定位
  • find_element(By.XX,value):根據By來宣告定位的方法,並且傳入對應定位方法的定位引數,比如By.ID跟By.CLASS_NAME等

另外,如果把element改為elements會定位所有符合條件的元素,返回一個List,比如:

find_elements_by_class_name
複製程式碼

Selenium定位到結點位置會返回一個WebElement型別的物件,可以呼叫下述方法來提取需要的資訊。

  • 獲取屬性:element.get_attribute()
  • 獲取文字:element.text
  • 獲取標籤名稱:element.tag_name
  • 獲取結點id:element.id

控制視窗大小

# 設定瀏覽器寬480,高800顯示
driver.set_window_size(480,800): 

# 全屏顯示
driver.maximize_window()
複製程式碼

頁面前進,後退,切換

在頁面操作過程中有時候點選某個連結會彈出新的視窗,這時候需要切換到新開啟的視窗上進行操作;

# 通過window_handles來遍歷
for handle in driver.window_handles:
    driver.switch_to_window(handle)

# 切換視窗
driver.switch_to.window("視窗名")

# 或通過window_handles來遍歷
for handle in driver.window_handles:
    driver.switch_to_window(handle)
    
# 前進
driver.forward()  

# 後退
driver.back()        
複製程式碼

重新整理動作

driver.refresh()
複製程式碼

清除文字,模擬按鍵輸入,點選動作

# clear()用於清除文字輸入框中的內容
driver.find_element_by_id("idinput").clear()

# send_keys()用於模擬鍵盤向輸入框裡輸入內容
driver.find_element_by_id("idinput").send_keys("username")

# click()用於進行點選操作
driver.find_element_by_id("loginbtn").click()
複製程式碼

提交表單

# 通過定位搜尋框並通過submit()提交搜尋框的內容,達到點選搜尋按鈕的效果
driver.find_element_by_id("query").submit()
複製程式碼

滑鼠動作

有時需要在頁面上模擬滑鼠操作,比如:單擊,雙擊,右鍵,按住,拖拽等,可以匯入ActionChains類:selenium.webdriver.common.action_chains.ActionChains,使用ActionChains(driver).XXX呼叫對應節點的行為。

  • click(element):單擊某個節點;
  • click_and_hold(element):單擊某個節點並按住不放;
  • context_click(element):右鍵單擊某個節點;
  • double_click(element):雙擊某個節點;
  • drag_and_drop(source,target):按住某個節點拖拽到另一個節點;
  • drag_and_drop_by_offset(source, xoffset, yoffset):按住節點按偏移拖拽
  • key_down:按下特殊鍵,只能用(Control, Alt and Shift),比如Ctrl+C
  • ActionChains(driver).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform();
  • key_up:釋放特殊鍵;
  • move_by_offset(xoffset, yoffset):按偏移移動滑鼠;
  • move_to_element(element):滑鼠移動到某個節點的位置;
  • move_to_element_with_offset(element, xoffset, yoffset):滑鼠移到某個節點並偏移;
  • pause(second):暫停所有的輸入多少秒;
  • perform():執行操作,可以設定多個操作,呼叫perform()才會執行;
  • release():釋放滑鼠按鈕
  • reset_actions:重置操作
  • send_keys(keys_to_send):模擬按鍵,
    比如輸入框節點.send_keys(Keys.CONTROL,'a') 全選輸入框內容,
    輸入框節點.send_keys(Keys.CONTROL,'x')剪下,
    模擬回退: 節點.send_keys(keys.RETURN);
    或者直接設定輸入框內容:輸入框節點.send_keys('xxx');
  • send_keys_to_element(element, *keys_to_send):和send_keys類似;

鍵盤事件

send_key()雖然可以模擬鍵盤輸入,但除此之外,還需要輸入其他按鍵,比如空格,這時候就需要用到Keys(); 對應類:selenium.webdriver.common.keys.Keys,使用send_keys(Keys.XX)輸入對應的內容即可;

  • BACK_SPACE:刪除鍵(BackSpace)(send_key(Keys.BACK_SPACE))
  • SPACE:空格鍵(Space)
  • TAB:製表鍵(TAB)
  • ESCAPE:回退鍵(Esc)
  • ENTER:Enter鍵(Enter)
  • CONTROL,'a':全選(Ctrl+A)(send_key(Keys.CONTROL,'a'))
  • CONTROL,'c':複製(Ctrl+C)
  • CONTROL,'x':剪下(Ctrl+X)
  • CONTROL,'v':貼上(Ctrl+V)
  • F1:鍵盤F1
  • ...
  • F12:鍵盤F12

頁面標題和連結

# 獲取當前網頁的標題
driver.title

# 獲取當前網頁的url
driver.current_url
複製程式碼

頁面等待

現在的網頁越來越多采用了 Ajax技術,這樣程式便不能確定何時某個元素完全載入出來了。
如果實際頁面等待時間過長導致某個dom元素還沒出來,但是你的程式碼直接使用了這個WebElement,那麼就會丟擲NullPointer的異常。
為了避免這種元素定位困難而且會提高產生ElementNotVisibleException的概率。
所以Selenium 提供了兩種等待方式,一種是隱式等待,一種是顯式等待。

  • 顯式等待:
    指定某個條件,然後設定最長等待時間。
    如果在這個時間還沒有找到元素,那麼便會丟擲異常,程式碼示例如下:
from selenium import webdriver
from selenium.webdriver.common.by import By
# WebDriverWait 庫,負責迴圈等待
from selenium.webdriver.support.ui import WebDriverWait
# expected_conditions 類,負責條件出發
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.PhantomJS()
driver.get("http://www.xxxxx.com/loading")
try:
    # 每隔10秒查詢頁面元素 id="myDynamicElement",直到出現則返回
    element = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, "myDynamicElement"))
    )
finally:
    driver.quit()
複製程式碼

如果不寫引數,程式預設會0.5s呼叫一次來檢視元素是否已經生成,如果本來元素就是存在的,那麼會立即返回。
下面是一些內建的等待條件,你可以直接呼叫這些條件,而不用自己寫某些等待條件了。

等待條件 描述
title_is 標題是內容
title_contains 標題包含某內容
presence_of_element_located 結點載入出來,傳入定位元組
visibility_of_element_located 結點課件,傳入定位元組
visibility_of 可見,傳入結點物件
presence_of_all_elements_located 所有結點載入出來
text_to_be_present_in_element 某個結點文字包含某文字
text_to_be_present_in_element_value 某個結點值包含某文字
frame_to_be_available_and_switch_to_it 載入並切換
invisibility_of_element_located 結點不可見
element_to_be_clickable 節點可點選
staleness_of 判斷結點是否仍在DOM,常用於判斷頁面是否已重新整理
element_to_be_selected 結點可選擇,傳入結點物件
element_located_to_be_selected 結點可選擇,傳入定位元組
element_selection_state_to_be 傳入結點物件和狀態,相等返回True,否則返回False
element_located_selection_state_to_be 傳入定位元組和狀態,相等返回True,否則返回False
alert_is_present 是否出現警告
  • 隱式等待:
    隱式等待比較簡單,就是簡單地設定一個等待時間,單位為秒,程式碼示例如下:
from selenium import webdriver
driver = webdriver.PhantomJS()
driver.implicitly_wait(10) # seconds
driver.get("http://www.xxxxx.com/loading")
myDynamicElement = driver.find_element_by_id("myDynamicElement")

如果不設定,就預設等待時間為0
複製程式碼

休眠sleep

有時候希望指令碼執行到某個位置做固定時間的休眠,這時候就需要用到sleep(),這個sleep方法是由Python的time模組提供,因此使用之前需要from time import sleep

# 休眠X秒
sleep(X) 
複製程式碼

多表單切換

在web應用中經常會遇到frame/iframe表單巢狀頁面的應用,webdriver只能在一個頁面上對元素識別與定位,對於frame/iframe無法直接定位;

這時候就需要通過switch_to.frame()方法將當前定位的主體切換為frame/iframe內嵌的的頁面中;

# 切換到iframe(id = "XX")
driver.switch_to.frame("XX")
複製程式碼

切換後就能正常操作元素了;

switch_to.frame()預設可以直接獲取表單的id或name屬性,但如果iframe沒有可用的id和name屬性呢?

# 先通過xpath定位到iframe
xf = driver.find_element_by_xpath("//*[@class="XX"]")

# 再將定位物件傳給switch_to.frame()方法
driver.switch_to.frame(xf)
複製程式碼

彈窗

對應類:selenium.webdriver.common.alert.Alert,用得不多,如果你觸發了某個事件,彈出了對話方塊,可以呼叫這個方法獲得對話方塊:alert = driver.switch_to_alert(),然後alert物件可以呼叫下述方法:

  • accept():確定
  • dismiss():關閉對話方塊
  • send_keys():傳入值
  • text():獲得對話方塊文字

上傳檔案

一般網頁上傳檔案,都是有一個瀏覽按鈕,選擇檔案點選上傳即可,但是對應做自動化測試來說,在選擇檔案那個過程是非常麻煩的;

其實,做過類似功能的同學會發現,瀏覽按鈕其實就是input標籤實現的上傳功能,可以看到是一個輸入框,居然如此,就可以用send_keys()來模擬;

driver.find_element_by_name("file").send_keys("C:\\jb.txt")
複製程式碼

下載檔案

執行設定檔案下載路徑;

options = webdriver.ChromeOptions()
prefs = {'profile.default_content_settings.popups': 0, 'download.default_directory': os.getcwd()}
options.add_experimental_option('prefs', prefs)
 
driver = webdriver.Chrome(chrome_options=options)
driver.get("http://pypi.Python.org/pypi/selenium")driver.find_element_by_partial_link_text("selenium-3.11.0-py2.py3-none-any").click()
複製程式碼

頁面截圖

driver.save_screenshot("截圖.png")

# 擷取當前視窗,並指定截圖圖片的儲存位置
dirver.get_screenshot_as_file("C:\\jb\\jb.jpg")
複製程式碼

Cookies

有些站點需要登入後才能訪問,用Selenium模擬登入後獲取Cookie,
然後供爬蟲使用的場景非常常見,Selenium提供了獲取,增加,刪除Cookies的函式,程式碼示例如下:

# 獲取所有Cookies
browser.get_cookies()

# 獲取name對應的cookie資訊
browser.get_cookie(name)

# 增加Cookies,是字典物件,必須要有name 和value
browers.add_cookie({xxx})
driver.add_cookie({"name":"jb","value":"jbtest"})

# 如果需要遍歷,則如下:
for cookie in driver.get_cookies():
    print("%s -> %s " % (cookie["name"],cookie["value"]))

# 刪除所有Cookies
browser.delete_cookies()

# 刪除Cookie資訊,name是要刪除的cookie的名稱,optionsString是該cookie的選項,目前支援的選項包括“路徑”和“域”
browser.delete_cookie(name,optionsString)
複製程式碼

實踐:

from selenium import webdriver
browser = webdriver.Chrome()

url = "https://www.baidu.com/"
browser.get(url)
# 通過js新開啟一個視窗
newwindow='window.open("https://www.baidu.com");'
# 刪除原來的cookie
browser.delete_all_cookies()
# 攜帶cookie開啟
browser.add_cookie({'name':'ABC','value':'DEF'})
# 通過js新開啟一個視窗
browser.execute_script(newwindow)
input("檢視效果")
browser.quit()
複製程式碼

這裡還是需要說下,add_cookie方法接受一個字典,字典中包含name,value,path,domain,secure,expiry,

正確的寫cookie格式:

cookie = {
    # "domain": ".58.com", #Firefox瀏覽器不能寫domain,如果寫了會報錯,谷歌需要寫否則也是報錯,這裡就是一個坑。其他瀏覽器沒測試不知道情況。
    'name': name,
    'value': value,
    "expires": "",
    'path': '/',
    'httpOnly': False,
    'HostOnly': False,
    'Secure': False,

}
name:cookie的名稱
value:cookie對應的值,動態生成的
domain:伺服器域名
expiry:Cookie有效終止日期
path:Path屬性定義了Web伺服器上哪些路徑下的頁面可獲取伺服器設定的Cookie
httpOnly:防指令碼攻擊
secure:在Cookie中標記該變數,表明只有當瀏覽器和Web Server之間的通訊協議為加密認證協議時
複製程式碼

為什麼要構造成這樣子,其實我們看下瀏覽器儲存的cookie格式就明白了。下圖就是谷歌瀏覽器的cookie 的截圖。

JB的閱讀之旅-Selenium2自動化測試實戰

程式碼應該這麼寫:

JB的閱讀之旅-Selenium2自動化測試實戰

這裡有個問題,cookie要key:value的格式,是非常麻煩的,尤其是像豆瓣那樣非常非常長的cookie,再手動一個一個改格式,這個工作量還不如重新用selenium寫一個登陸操作;

fiddler轉包的cookie格式是這樣的:

JB的閱讀之旅-Selenium2自動化測試實戰

一個一個改會崩潰的;所以遇到cookie很長的情況,還不如寫一個登陸指令碼儲存吧~

執行JS語句

雖然webdriver提供瀏覽器的前進和後退,但是並不提供滾動瀏覽器的操作,因此來藉助JS來控制瀏覽器的滾動條;

driver.execute_script(js語句)
複製程式碼

比如滾動到底部的程式碼示例如下:

js = document.body.scrollTop=10000
driver.execute_script(js)
複製程式碼

又如設定瀏覽器視窗的滾動條位置:

js = "window.scrollTo(100,450)"
driver.excute_script(js)
複製程式碼

向文字框輸入文字資訊:

text = "jbtest"
js = "var sum=document.getElementById("id"); sum.value='"+text+ " ';"
driver.excute_script(js)
複製程式碼

處理HTML5 的視訊播放

HTML5定義了一個新的元素video,指定了一個標準的方式來嵌入電影片段;

from selenium import webdriver
from time import sleep

driver = webdriver.Firefox()
driver.get("http://videojs.com/")

video = driver.find_element_by_xpath("body/Setion[1]/div/video")

# 返回播放檔案地址
url = driver.execute_script("return arguments[0].currentSrc;",video)

# 播放視訊
driver.execute_script("return arguments[0].play()",video)

# 暫停視訊
driver.execute_script("arguments[0].pause()",video)
複製程式碼

JS函式有個內建的物件叫做arguments; arguments物件包含了函式呼叫的引數陣列,[0]表示取物件的第一個值;

  • currentSrc:返回當前音訊/視訊的URL,如果未設定音訊/視訊,則返回空字串;
  • load():控制著視訊的載入
  • play():控制著視訊的播放
  • pause():控制著視訊的暫停

Headless

在介紹Headless之前,必須介紹下PhantomJS,
PhantomJS是沒有介面的瀏覽器,特點:
會把網站載入到記憶體並執行頁面上的JavaScript,因為不會展示圖形介面,所以執行起來比完整的瀏覽器要高效

而上面的例子,每次執行後,都會開啟瀏覽器,很麻煩,這麼看,PhantomJs是剛需啊;

但這裡不打算介紹PhantomJs,因為18年4月份,維護者宣佈退出PhantomJs,意味著這個專案不再維護了;而同時,Chrome和FireFox也開始 提供Headless模式(無需調起瀏覽器),所以,後面的phantomjs小夥伴會遷移到這兩個瀏覽器上;

注意:Windows Chrome需要60以上的版本才支援 Headless模式,linux,unix系統需要 chrome瀏覽器 >= 59

啟用Headless模式也很簡單,以上面開啟百度的程式碼舉例,程式碼如下:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

chrome_option = Options()
chrome_option.add_argument("--headless")
chrome_option.add_argument("--disable-gpu")

browser = webdriver.Chrome(chrome_options=chrome_option)  # 呼叫本地的Chrome瀏覽器
browser.get('http://www.baidu.com')  # 請求頁面,會開啟一個瀏覽器視窗
html_text = browser.page_source  # 獲得頁面程式碼
browser.quit()  # 關閉瀏覽器
print(html_text)
複製程式碼

就是多了設定chrome_option這幾步,執行後,就不會再彈出瀏覽器了,是不是很方便??

設定自定義請求頭

from selenium import webdriver
# 進入瀏覽器設定
options = webdriver.ChromeOptions()
# 設定中文
options.add_argument('lang=zh_CN.UTF-8')
# 更換頭部
options.add_argument('user-agent="Mozilla/5.0 (iPod; U; CPU iPhone OS 2_1 like Mac OS X; ja-jp) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.1 Mobile/5F137 Safari/525.20"')
browser = webdriver.Chrome(chrome_options=options)
url = "https://httpbin.org/get?show_env=1"
browser.get(url)
browser.quit()
複製程式碼

溫馨提示:遇到JS載入的問題,建議先嚐試破解JS,不行再用selenium,selenium屬於無腦型別,而且效率比較差,假如你有1W個網站,都跑一趟,估計要一天了;

大部分selenium相關的操作都介紹完了,先留個印象,那接下來,讓我們看看怎麼用selenium來獲取豆瓣驗證碼captcha這個屬性吧;

    "Cookie":"your cookie"   #這裡需要輸入你自己的cookie資訊,如果遇到轉義字元,轉
        義字元前面加\即可
複製程式碼

Selenium詳細介紹

什麼是Selenium

Selenium主要用於Web應用程式的自動化測試;

特點:

  • 開源,免費;
  • 多瀏覽器支援:Firefox、Chrome、IE、Opera、Edge;
  • 多平臺支援:Linux、Windows、MAC;
  • 多語言支援:Java、Python、Ruby、C#、JavaScript、C++;
  • 對Web頁面有良好的支援;
  • API簡單、靈活(用開發語言驅動)
  • 支援分散式測試用例執行

Selenium有兩個版本:Selenium 1.0 和Selenium 2.0; Selenium不是由單獨一個工具構成的,而是由一些外掛、類庫組成,每個部分都有起特點和應用場景;

Selenium 1.0家譜:

JB的閱讀之旅-Selenium2自動化測試實戰

Selenium IDE

Selenium IDE是嵌入到Firefox瀏覽器中的一個外掛,實現簡單的瀏覽器操作的錄製與回放功能;

官方給出它自身作用的定位:

快速地建立bug重現指令碼,在測試人員測試過程中,發現bug之後可以通過IDE將重現的步驟錄製下來,以幫助開發人員
更容易的重現bug;
複製程式碼

那就可以理解,IDE的重點在於錄製,避免不會寫程式碼的同學,而且每次寫xpath也會很煩;

安裝

線上安裝 通過 firefox 瀏覽器訪問 selenium;

下載頁面:docs.seleniumhq.org/download/

在 selenium IED 下載介紹部分,點選版本號連結;

JB的閱讀之旅-Selenium2自動化測試實戰

firefox 瀏覽器將自動識別需要下載的 selenium IED 外掛,,點選 Install Now 按鈕,安裝 selenium IED 外掛。

安裝完成後重啟 firefox 瀏覽器,通過選單欄“Tools(工具)”---> selneium IDE 可以開啟,或通過 Ctrl+Alt+S 快捷鍵開啟。

JB的閱讀之旅-Selenium2自動化測試實戰

但是實際,上面的url,試了半天都訪問不了,另外還有,如果非Firefox瀏覽器是不是就用不了IDE?

外掛安裝 非也,還有個外掛安裝的方法,此方法來自小敏同學親測可行,Python2.7版本,Firefox40.0版本

1)python2.7 mac/Linux自帶,不用裝; Windows需要手動安裝,要裝的小夥伴自行百度,so easy ~

2)selenium 由於selenium IDE在新版本firefox上並不支援,沒有錄製功能寫起來還是挺費神的,建議保守的都選擇舊版本。

如果已經安裝了selenium3,需要先解除安裝;

檢視selenium版本命令:
pip show selenium

解除安裝selenium命令:
pip uninstall selenium
複製程式碼

selenium用命令列pip install selenium==2.53.6安裝時,由於被牆了,選擇下載安裝包自行安裝,步驟如下:

  • 下載安裝包selenium-2.53.6.tar.gz
  • 將安裝包放到python2.7的site-packages目錄下,解壓,比如目錄是/Library/Python/2.7/site-packages/
  • cd到上一步解壓後的selenium目錄下,python setup.py install,安裝完成,檢視版本號確認安裝成功

3)下載安裝firefox 40.0版本

4)下載selenium_ide-2.9.1-fx.xpi,拖到firefox裡面安裝好後,firefox右上角多出selenium IDE外掛入口

JB的閱讀之旅-Selenium2自動化測試實戰

5)下載firebug-2.0.16-fx.xpi,拖到firefox裡面安裝好後,firefox右上角多出firebug外掛入口

JB的閱讀之旅-Selenium2自動化測試實戰

至此,環境安裝完成。

6)錄製自動化指令碼 點選firefox右上角selenium IDE外掛圖示,進入selenium IDE主介面;

  • 在下圖序號1紅框中,輸入你要測試的web url;
  • 在下圖序號2紅框中,調節你要執行用例的速度,一般建議調到中間;
  • 在下圖序號3紅框中,點選錄製按鈕開始錄製;
  • 在下圖序號4紅框中,對錄製結果進行調節,可以增刪改事件、引數;
  • 在下圖序號3紅框中,點選停止錄製按鈕停止錄製;
  • 在下圖序號5紅框中,點選按鈕開始執行用例;
  • 可以在選單中選擇檔案——export test case as——python 2/unittest/web driver,將指令碼匯出為python,本地編輯直接指令碼呼叫。

JB的閱讀之旅-Selenium2自動化測試實戰

7)優化指令碼 上步中最後匯出的指令碼,只包含了操作,沒有包含斷言結果判斷,也缺少容錯,想要持續整合自動生成結果,還需要自己按需補充。

Selenium Grid

是一種自動的測試輔助功能,Grid通過利用現有的計算機基礎設施,能加快Web-App的功能測試;

利用Grid可以很方便地實現在多臺機器上和異構環境中執行測試用例;

聽上去會一臉懵逼,簡單說,Selenium Grid可以解決重複執行測試和多瀏覽器相容測試的亮點,並且是使用分散式執行測試;

那分散式是什麼概念?簡單的說就是老大收到任務,分發給手下去幹;

通過Selenium Grid的可以控制多臺機器多個瀏覽器執行測試用例,分散式上執行的環境在Selenium Grid中稱為node節點。

舉例說明一下,比如用例上萬,一臺機器執行全部測試用例耗時5個小時,而如果需要覆蓋主流瀏覽器比如Chrome、Firefox,加起來就是10個小時;

最笨的辦法就是另外拿臺機器,然後部署環境,把測試用例分開去執行然後合併結果即可。

而Selenium也想到了這點,所以有了Selenium Grid的出現,它就是解決分散式執行測試的痛點。

工作原理

Selenium Grid實際它是基於Selenium RC的,而所謂的分散式結構就是由一個hub節點和若干個node代理節點組成。

Hub用來管理各個代理節點的註冊資訊和狀態資訊,並且接受遠端客戶端程式碼的請求呼叫,然後把請求的命令轉發給代理節點來執行。

下面結合環境部署來理解Hub與node節點的關係。

環境部署

1)下載selenium-server-standalone-2.53.1.jar

下載地址:selenium-release.storage.googleapis.com/index.html

JB的閱讀之旅-Selenium2自動化測試實戰

2)啟動hub

使用快捷鍵WIN+R開啟執行對話方塊,輸入cmd確定,進入命令視窗

JB的閱讀之旅-Selenium2自動化測試實戰

進入selenium-server-standalone-2.53.1.jar包的位置,如E:\selenium;

JB的閱讀之旅-Selenium2自動化測試實戰

啟動hub,命令如下:

 java -jar selenium-server-standalone-2.53.1.jar -role hub -maxSession 10 -port 4444
複製程式碼

JB的閱讀之旅-Selenium2自動化測試實戰

引數 解釋
role hub 啟動執行hub
port 設定埠號,hub的預設埠是4444,這裡使用的是預設的埠,當然可以自己配置
maxSession 最大會話請求,這個引數主要要用併發執行測試用例,預設是1,建議設定10及以上

瀏覽器開啟地址:http://localhost:4444/grid/console,出現如下圖表示hub啟動成功。

JB的閱讀之旅-Selenium2自動化測試實戰

啟動hub後,就需要執行節點啦,最少都要有一個node節點,不然hub就成空頭司令了;而node節點可以與hub在同一臺機器上執行,演示一個node節點與hub同機,另一個node節點啟動了一臺虛擬機器。

名稱 IP
hub機 192.168.0.245
node1機 192.168.0.245
node2機 192.168.0.183

3)啟動node節點1

node1節點,配置firefox瀏覽器,執行下面命令:

java -jar selenium-server-standalone-2.53.1.jar -role node -port 5555 -hub http://192.168.0.245:4444/grid/register -maxSession 5 -browser browserName=firefox,seleniumProtocol=WebDriver,maxInstances=5 ,platform=WINDOWS,version=45.0.2
複製程式碼

JB的閱讀之旅-Selenium2自動化測試實戰

沒有報錯則再次重新整理一下http://localhost:4444/grid/console的訪問會發現node節點已經顯示,表示啟動成功;

JB的閱讀之旅-Selenium2自動化測試實戰

引數 解釋
role node 啟動執行node節點
port 555 指定node節點埠
hub http://192.168.0.245:4444/grid/register hub機地址
maxSession 5 node節點最大會話請求
browser browserName=firefox,seleniumProtocol=WebDriver, maxInstances=5,platform=WINDOWS,version=45.0.2 這個就是設定瀏覽器的引數啦
browserName表示瀏覽器名字,maxInstances表示最大例項,可以理解為最多可執行的瀏覽器數,不能大於前面maxSession的值,否則可能會出錯;platform表示作業系統;version表示瀏覽器版本。
複製程式碼

4)啟動node節點2

node2節點,在目錄放了chromedriver.exe檔案,這裡要提示一下,這個chromedriver.exe檔案前面說過下載地址了,主要是版本需要與系統中安裝的chrome瀏覽器匹配;

JB的閱讀之旅-Selenium2自動化測試實戰
執行下面命令:

java -jar selenium-server-standalone-2.53.1.jar -role node -port 6666 -hub http://192.168.0.245:4444/grid/register -Dwebdriver.chrome.driver=chromedriver.exe -maxSession 5 -browser browserName=chrome,seleniumProtocol=WebDriver,maxInstances=5,platform=WINDOWS
複製程式碼

JB的閱讀之旅-Selenium2自動化測試實戰

沒有報錯則再次重新整理一下http://localhost:4444/grid/console的訪問會發現node節點已經顯示,表示啟動成功;

如果使用的chromedriver.exe與selenium-server-standalone-2.53.1版本或者瀏覽器chrome版本不匹配都會報錯提示,具體原因需要具體解決。

JB的閱讀之旅-Selenium2自動化測試實戰

引數 解釋
Dwebdriver.chrome.driver=chromedriver.exe 瀏覽器外掛,如果是其他瀏覽器就寫對應的名字
如firefox: -Dwebdriver.firefox.driver=geckodriver.exe
注意多了這個引數注意是chromedriver.exe需要指定,而對於Webdriver2是支援geckodriver所以不需要指定geckodriver,但前提是firefox瀏覽器版本不能大於46,所以看到node節點1使用的是45版本的瀏覽器。
複製程式碼

使用

當例項化Hub遠端時,會根據配置去匹配Hub上註冊的node代理節點,匹配成功後轉發給代理節點,這時候代理節點會生成sessionid啟動瀏覽器,然後響應給Hub說一切準備就緒,Hub也會把這個sessionid響應給客戶端,接下來的客戶端的程式碼發來的請求都會被Hub轉發給這個代理節點來執行。這裡實際上整個流程與Selenium1.0的原理是一樣的,只是多了Hub這一層。

DesiredCapabilities capability = new DesiredCapabilities();
capability.setBrowserName("chrome");
capability.setPlatform(Platform.WINDOWS);
try {
WebDriver driver = new RemoteWebDriver(new URL("http://192.168.0.245:4444/wd/hub"), capability);
driver.get("http://www.baidu.com");
driver.quit();
} catch (MalformedURLException e) {
  e.printStackTrace();
}
複製程式碼

根據上面程式碼會發現node節點2執行,如果把setBrowserName()方法裡面的傳參改了firefox就會在node節點1執行。表示Selenium Grid環境搭建完成。

另外客戶端還可以直接使用node節點執行程式碼,這樣的方式就與selenium1.0一模一樣啦,看下面程式碼:

DesiredCapabilities capability = new DesiredCapabilities();
capability.setBrowserName("chrome");
capability.setPlatform(Platform.WINDOWS);
try {
WebDriver  driver = new RemoteWebDriver(new URL("http://192.168.0.183:6666/wd/hub"), capability);
driver.get("http://www.baidu.com");
driver.quit();
} catch (MalformedURLException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
複製程式碼

要注意例項化driver物件時填寫的服務地址是node節點的地址,這樣就會直接去節點執行;還有一個注意的就是DesiredCapabilities配置,一定要設定該節點執行引數正確的瀏覽器、瀏覽器版本、系統,如果引數不對都會出現報錯。

Selenium RC

Selenium RC(Remote Control)是Selenium家族的核心部分; 支援多種不同語言編寫的自動化測試指令碼,通過Selenium RC的伺服器作為代理伺服器去訪問應用,從而達到測試目的;

selenium RC 分為 Client Libraries 和 Selenium Server; Client Libraries 庫主要主要用於編寫測試指令碼,用來控制 selenium Server 的庫。 Selenium Server 負責控制瀏覽器行為;

總的來說,Selenium Server 主要包括 3 個部分Launcher、Http Proxy、Core。

其中 Selenium Core 是被 Selenium Server 嵌入到瀏覽器頁面中的。 其實 Selenium Core 就是一堆 JS 函式的集合,就是通過這些 JS 函式,我們才可以實現用程式對瀏覽器進行操作。

Launcher 用於啟動瀏覽器,把 selnium Core 載入到瀏覽器頁面當中,並把瀏覽器的代理設定為 Selenium Server 的Http Proxy。

Selenium 2.0

Selenium 2.0 是把 WebDriver 加入到了這個家族中; 簡單用公式表示為:

selenium 2.0 = selenium 1.0 + WebDriver

在 selenium 2.0 中主推的是 WebDriver ,WebDriver 是 selenium RC 的替代品; 那麼 selenium RC 與 webdriver 主要有什麼區別呢?

Selenium RC 在瀏覽器中執行 JavaScript 應用,使用瀏覽器內建的 JavaScript 翻譯器來翻譯和執行 selenium 命令)。

WebDriver 通過原生瀏覽器支援或者瀏覽器擴充套件直接控制瀏覽器。

WebDriver 針對各個瀏覽器而開發,取代了嵌入到被測 Web 應用中的 JavaScript。與瀏覽器的緊密整合支援建立更高階的測試,避免了JavaScript 安全模型導致的限制。
除了來自瀏覽器廠商的支援,WebDriver 還利用作業系統級的呼叫模擬使用者輸入。
複製程式碼

WebDriver原理

WebDriver是按照Server-Client的設計模式設計的;

Server端就是Remote Server,可以是任意的瀏覽器; 當我們的指令碼啟動瀏覽器後,該瀏覽器就是Remote Server,職責就是等待Client傳送請求並做出響應;

Client端簡單理解就是測試程式碼; 指令碼的行為是以http請求的方式傳送給被測試的瀏覽器,瀏覽器接受請求,執行相應操作,並在response中返回執行狀態,返回等資訊;

WebDriver的工作流程:

  • WebDriver啟動目標瀏覽器,並繫結到指定埠;啟動的瀏覽器例項將作為WebDriver的Remote Server;
  • Client端通過CommandExcuter傳送HTTPRequest給Remote Server 的偵聽埠;
  • Remote Server需要依賴原生的瀏覽器元件來轉化瀏覽器的native呼叫;

小結

斷斷續續的看了這本書很久很久,還是因為自己懶;

看完這本書,對selenium的api至少留個印象,最重要的還是找控制元件的8種方式,一般如果Jb去面試,也會問這個問題,當然也會有selenium的原理以及2.0跟1.0的區別,不過後面幾點只是做簡單瞭解,不做任何評價;

可別忘記了,selenium對於是可以獲取JS載入後的頁面內容,如果想爬一個網頁,而且內容是JS載入的,如果不想研究JS,就用selenium吧,賊好用的玩意;

立個flag,之前太忙了,導致一個月沒更新部落格,感覺人都廢了,因此立一個,一週更新一篇的flag,看能堅持多久吧~

最後,貼這個這本書電子版的連結:

https://pan.baidu.com/s/1b8T6Iq?errno=0&errmsg=Auth%20Login%20Sucess&&bduss=&ssnerror=0&traceid=
複製程式碼

這裡說明下,電子版跟實體書還是有點不一樣,如果只是用來查api,看這篇文章或者看電子書就好了,主要的內容沒什麼變化;

謝謝大家~

JB的閱讀之旅-Selenium2自動化測試實戰

相關文章