《Selenium自動化測試實戰:基於Python》之 基於Docker與Selenium Grid的測試技術

                       基於Docker與Selenium Grid的測試技術                        

10.1  Selenium Grid簡介

  儘管即將推出的Selenium 4.0對Selenium Grid的一些新特性進行了說明(截至本書完稿時,Selenium 4.0還沒有正式發佈),可是從目前看,官方並無太多詳細文檔供你們參考,因此本書仍結合目前普遍使用的Selenium Grid 版本進行講解。參見官網上的描述,Selenium Grid是智能代理服務器,容許Selenium將測試命令路由到遠程Web瀏覽器實例,目的是提供一種在多臺計算機上並行運行測試的簡便方法。使用Selenium Grid,一臺服務器能夠充當將JSON格式的測試命令路由到一個或多個已註冊Grid節點的中樞,以得到對遠程瀏覽器實例的訪問。Selenium Grid容許咱們在多臺計算機上並行運行測試,並集中管理不一樣的瀏覽器版本和瀏覽器配置。如圖10-1所示,能夠看到Selenium Grid主要由Hub和Node兩部分構成。可使用Python、Java、C#等語言編寫和測試Selenium腳本,每一個Selenium Grid僅有一個Hub,客戶端腳本能夠指定鏈接到這個Hub(主控節點或者叫集線器),Hub接收客戶端腳本的運行測試請求,同時將這些測試請求分發到已註冊的一個或多個節點以執行並收集運行結果。Selenium Grid中能夠有一個或多個Node(節點)。做爲節點的機器沒必要與Hub或其餘Node具備相同的操做系統或瀏覽器。換言之,某個Node可能使用的是Windows操做系統,而在Windows操做系統中安裝的是Internet Explorer瀏覽器,另外的Node可能使用的是Linux操做系統、macOS,而它們安裝的瀏覽器多是Firefox、Safari、Chrome等。這些Node的設置結合測試來說,就是看想作哪些操做系統和瀏覽器版本的兼容性測試,在實際工做中請結合測試執行計劃和策略進行選擇。javascript

 

圖10-1  Selenium Grid的組件構成html

10.2  基於Docker的Selenium Grid的相關配置

  Docker Hub提供了Selenium Grid的相關鏡像文件以供使用,如圖10-2所示。java

 

圖10-2  Selenium Grid的相關鏡像文件node

  這裏,咱們使用docker pull命令分別將這3個鏡像文件拉取下來,對應的拉取命令以下。python

docker pull selenium/hub
docker pull selenium/node-chrome
docker pull selenium/node-firefox

  拉取鏡像文件到本地後,可使用docker images命令查看一下相關鏡像的信息,如圖10-3所示。android

 

圖10-3  Selenium Grid的相關鏡像信息web

  這裏咱們先測試一下Hub與Node之間的連通性。chrome

  建立並啓動Hub容器,如圖10-4所示。docker

 

圖10-4  建立並啓動Hub容器瀏覽器

  建立並啓動 chromenode容器節點,如圖10-5所示。

 

圖10-5  建立並啓動chromenode容器節點

  建立並啓動 firefoxnode容器節點,如圖10-6所示。   

 

圖10-6  建立並啓動firefoxnode容器節點

  接下來,在本機瀏覽器的地址欄中輸入http://localhost:4444/grid/console並按Enter鍵,打開Selenium Grid的控制檯,出現圖10-7所示頁面。

 

圖10-7  Selenium Grid的控制檯

  從圖10-7可知,當前使用的Selenium Grid 版本爲3.141.59,鏈接到Hub的兩個Node中,IP地址爲172.17.0.4的Linux操做系統使用的是75.0版本的Firefox瀏覽器,IP地址爲172.17.0.3的Linux操做系統使用的是81.0.4044.92版本的Chrome瀏覽器。默認狀況下,Hub使用的是4444端口,而Node在本例中使用的是5555端口。若是在同一個容器中出現端口衝突等狀況,則須要根據實際狀況進行調整以免端口衝突狀況再次發生。

10.3  基於Docker + Selenium Grid的案例演示

       下面結合Bing搜索案例在Chrome和Firefox瀏覽器中實現兼容性測試。在通過對Selenium、Docker和Selenium Grid相關知識的學習後,你想到了什麼?是否是經過使用Docker + SeleniumGrid就可以完成基於不一樣瀏覽器的兼容性測試呢?是的,這確實是個好主意。

  可是,爲了讓Selenium測試腳本在不一樣的瀏覽器中運行,又須要作些什麼呢?

  在腳本設計上,須要作一些改變。一般狀況下,要在腳本運行時指定主機和端口號,使用的腳本以下。

import time
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

driver = webdriver.Remote(
    command_executor='http://192.168.1.102:4444/wd/hub',
    desired_capabilities=DesiredCapabilities.CHROME)
base_url = 'https://cn.bing.com'
driver.get(base_url)
driver.save_screenshot('chrome.png')
driver.close()

  一般在執行時,只須要指定Hub的地址(http://192.168.1.102:4444/wd/hub)。這裏宿主機的IP地址信息如圖10-8所示,Hub會將腳本自動分配給Node去執行。

 

圖10-8  宿主機的IP地址信息

  • command_executor:選填參數,可指定遠程服務器的URL字符串或自定義遠程鏈接,默認爲http://127.0.0.1:4444/wd/hub。
  • desired_capabilities參數:必填參數,可根據狀況配置爲在啓動瀏覽器會話時請求功能字典。這裏咱們使用的是DesiredCapabilities.CHROME,對應的源代碼以下所示。
class DesiredCapabilities(object):

    """
    Set of default supported desired capabilities.
    Use this as a starting point for creating a desired capabilities object for
    requesting remote webdrivers for connecting to selenium server or selenium grid.
    Usage Example::
         from selenium import webdriver
        selenium_grid_url = "http://198.0.0.1:4444/wd/hub"
        capabilities = DesiredCapabilities.FIREFOX.copy()
        capabilities['platform'] = "WINDOWS"
        capabilities['version'] = "10"
        driver = webdriver.Remote(desired_capabilities=capabilities,
                                  command_executor=selenium_grid_url)
    Note: Always use '.copy()' on the DesiredCapabilities object to avoid the side
    effects of altering the Global class instance.
    """

    FIREFOX = {
        "browserName": "firefox",
        "acceptInsecureCerts": True,
    }

     INTERNETEXPLORER = {
        "browserName": "internet explorer",
        "version": "",
        "platform": "WINDOWS",
    }

     EDGE = {
        "browserName": "MicrosoftEdge",
        "version": "",
        "platform": "ANY"
    }

    CHROME = {
        "browserName": "chrome",
        "version": "",
        "platform": "ANY",
    }

     OPERA = {
        "browserName": "opera",
        "version": "",
        "platform": "ANY",
    }

     SAFARI = {
        "browserName": "safari",
        "version": "",
        "platform": "MAC",
    }

     HTMLUNIT = {
        "browserName": "htmlunit",
        "version": "",
        "platform": "ANY",
    }

     HTMLUNITWITHJS = {
        "browserName": "htmlunit",
        "version": "firefox",
        "platform": "ANY",
        "javascriptEnabled": True,
    }

     IPHONE = {
        "browserName": "iPhone",
        "version": "",
        "platform": "MAC",
    }

    IPAD = {
        "browserName": "iPad",
        "version": "",
        "platform": "MAC",
    }

    ANDROID = {
        "browserName": "android",
        "version": "",
        "platform": "ANDROID",
    }

     PHANTOMJS = {
        "browserName": "phantomjs",
        "version": "",
        "platform": "ANY",
        "javascriptEnabled": True,
    }

     WEBKITGTK = {
        "browserName": "MiniBrowser",
        "version": "",
        "platform": "ANY",
    }

    WPEWEBKIT = {
        "browserName": "MiniBrowser",
        "version": "",
        "platform": "ANY",
    }

  從DesiredCapabilities類的源碼可知DesiredCapabilities.CHROME是DesiredCapabilities類定義的字典對象。

  這裏採用多線程的方式,分別在Chrome和Firefox瀏覽器中執行Bing搜索業務。

  Grid_Test.py文件的內容以下。

from threading import Thread
from selenium import webdriver
from time import sleep,ctime
from selenium.webdriver.common.by import By

def Test_Bing(Host, Browser):
    caps = {'browserName': Browser}  
    driver = webdriver.Remote(command_executor=Host, desired_capabilities=caps)
    driver.get('http://www.bing.com')
    driver.find_element(By.ID,'sb_form_q').send_keys('異步社區')
    driver.find_element(By.ID,'sb_form_go').click()
    PicName=Browser+'_result'+'.png'
    driver.save_screenshot(PicName)
    assert ('沒有與此相關的結果' not in driver.page_source)
    sleep(2)
    driver.close()

if __name__ == '__main__':
    pcs = {'http://192.168.1.102:4444/wd/hub': 'chrome',
             'http://localhost:4444/wd/hub': 'firefox'
             }
    threads = []
    tds=range(len(pcs))
    #建立線程
    for host, browser in pcs.items():
        t = Thread(target=Test_Bing, args=(host, browser))
        threads.append(t)
    #啓動線程
    for i in tds:
        threads[i].start()
    for i in tds:
        threads[i].join()

  從上面的腳本能夠看到,這裏建立了一個名爲Test_Bing()的函數,它包含兩個參數,分別用來指定主機和瀏覽器。這個函數的執行意圖就是根據遠程服務器的URL字符串和傳入的瀏覽器名稱字符串,在對應的瀏覽器中執行搜索業務,且搜索詞爲「異步社區」。而後對執行結果進行截圖,截圖的名稱爲對應瀏覽器的名稱加上_result.png,最後對搜索結果進行斷言。須要說明的是,這裏進行截圖的目的不只是看一下結果,還要看一下執行過程。在使用Selenium Grid時,因爲測試過程當中不會出現瀏覽器,所以看不到執行過程。若是還想看看不一樣的容器在執行過程當中的界面,那麼可使用VNC Viewer鏈接到對應的容器(但須要下載對應的selenium/node-firefox-debug和selenium/node-chrome- debug鏡像文件,以debug結尾的鏡像都帶有VNC服務器,在本機上安裝VNC客戶端後便可遠程鏈接。5900端口爲VNC Viewer的監聽端口,所以作了端口映射),如圖10-9和圖10-10所示。

 

圖10-9  建立並啓動Debug版本的節點容器

 

圖10-10  使用VNC Viewer觀察節點容器的腳本執行狀況

  事實上,這對於測試工做並無太多意義,於是不作太多文字贅述。

  主函數定義了一個包含兩個元素的字典,這裏雖然使用了同一個地址,但採用的是兩種不一樣的表示方式(宿主機的IP地址爲192.168.1.102),而localhost也表示宿主機。那麼爲何不都用192.168.1.102或localhost呢?這是由於字典的鍵(key)是不容許重複的。接下來,咱們建立了一個線程列表,以pcs字典的鍵、值做爲Test_Bing()函數的參數添加到這個線程列表中,然後啓動這個線程列表中的各個線程。

  在運行腳本前,須要保證建立並啓動Hub和Node容器(這裏應用的是非Debug版本的Node鏡像),如圖10-11所示。

 

圖10-11  建立並啓動Hub和Node容器

  腳本執行完畢後,將會生成chrome_result.png和firefox_result.png兩個圖片文件,如圖10-12所示。

 

  圖10-12  腳本執行完畢後生成的圖片文件

  在本次兼容性測試中,這兩個瀏覽器執行了相同的Bing搜索業務,它們的頁面展現、佈局、內容基本是相同的,但存在兩個小的問題。第一個小問題就是在Chrome瀏覽器中搜索到的結果有855 000條(見圖10-13),而在Firefox瀏覽器中搜索到的結果有859 000條(見圖10-14),它們是不一致的。另外一個小問題是,Firefox瀏覽器會顯示Sign in和登陸圖標,而Chrome瀏覽器沒有。從理論上講,這是兩個嚴重度級別較低的小Bug,建議針對這兩個小的差別,與產品及研發人員再確認一下,產品、測試及研發人員應統1、明確需求,明確後再修改需求或代碼,使二者保持一致。

 

圖10-13  在Chrome瀏覽器中搜索到的結果

 

 

圖10-14  在Firefox瀏覽器中搜索到的結果

京東:https://item.jd.com/13123910.html

噹噹:http://product.dangdang.com/29204520.html

答疑解惑羣:50788246

相關文章
相關標籤/搜索