1. 程式人生 > 實用技巧 >Selenium Grid + Maven + TestNG + Jenkins 完成Selenium 分散式併發測試

Selenium Grid + Maven + TestNG + Jenkins 完成Selenium 分散式併發測試

Selenium Grid 是什麼?

  Selenium Grid 是一個可以方便的讓你指令碼執行在不同的平臺以及不同的瀏覽器上的一個框架。Selenium Grid 分1和2兩個版本,其中Selenium Grid 2的釋出還晚於Selenium 2.0,也就是說Selenium Grid 2 並不是和Selenium 2.0 一起釋出的,但是Selenium Grid 2基本上支援Selenium 2.0的所有功能。

Selenium Grid 基本結構

  如上圖,Selenium Grid 由一個Hub節點和若干個Node節點組成。 其中Hub節點主要用於管理各個Node節點的註冊及其狀態,並接收Selenium Scripts指令碼,然後轉發給各個Node節點去執行,所以Hub本身節點是不執行指令碼的,Hub是做指令碼分發,真正執行指令碼都是放於Node節點上。既然Hub 會分發指令碼,那麼免去了一個一個Node機器上去拷貝你指令碼的麻煩啦。

何時需要 Selenium Grid

  在瞭解了什麼是 Selenium Grid 和其基本結構後,那麼我們開始關心我們何時需要它呢?下面列出兩點:

1. 當你的指令碼需要在不同的系統和瀏覽器執行時,也就是測試需要考慮各種瀏覽器相容性時。
2. 當你想縮短你的測試執行時間時。

當你開始考慮上面兩個問題時,那麼可以考慮使用Selenium Grid .

怎麼使用

 注意:Selenium Grid 是用java開發的框架,所以你想執行這個框架,你需要有java環境。Java環境的搭建可以參考http://www.jianshu.com/p/74a5ea7fd369

下載jar包

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

,選取最新版本,例如寫這個文章時最新版本是2.53,那麼進入2.53資料夾下載 selenium-server-standalone-2.53.0.jar 檔案便可。

啟動Hub 節點:

在控制檯(終端)輸入:java -jar selenium-server-standalone-2.53.0.jar -role hub
出現類似如下圖資訊便表示Hub啟動成功:


hub啟動成功.png

這時你可以瀏覽器開啟http://localhost:4444/grid/console,可以看到Hub管理頁面。


點選 view config,可以檢視到當前hub節點的一些配置預設配置資訊,例如:
port : 4444

這個是hub 預設的埠號;

throwOnCapabilityNotPresent : true預設為 true,表示當前hub只有在有node存在時,才會接受測試請求。為false 則反之;

capabilityMatcher : org.openqa.grid.internal.utils.DefaultCapabilityMatcher這是一個實現了CapabilityMatcher介面的類,預設指向org.openqa.grid.internal.utils.DefaultCapabilityMatcher該類用於實現grid在分佈測試任務到對應node時所使用的匹配規則,如果想要更精確的測試分配規則,那麼就註冊一個自己定義的匹配類;

prioritizer : null這是一個實現了Prioritizer介面的類。設定grid執行test任務的優先邏輯;預設為null,那個指令碼先到那個先執行;

newSessionWaitTimeout : -1預設-1,即沒有超時;指定一個新的測試session等待執行的間隔時間。即一個代理節點上前後2個測試中間的延時時間,單位為毫秒;

browserTimeout : 0瀏覽器無響應的超時時間,預設為0表示沒有超時時間

修改 hub 的配置

想要修改 hub 的配置有兩種方法。

通過命令修改

例如假設我的 4444埠被別的程式佔用了,我想修改預設的埠為4445,則如下:
java -jar selenium-server-standalone-2.53.0.jar -role hub -port 4445

通過Json檔案修改配置:

  1. 新建個json格式的檔案,內容如下(這裡僅僅修改了maxSession的配置,預設是5),並放於跟Grid jar包同一目錄:
    { "host": null, "port": 4444, "newSessionWaitTimeout": -1, "servlets" : [], "prioritizer": null, "capabilityMatcher": "org.openqa.grid.internal.utils.DefaultCapabilityMatcher", "throwOnCapabilityNotPresent": true, "nodePolling": 5000, "cleanUpCycle": 5000, "timeout": 300000, "browserTimeout": 0, "maxSession": 10 }
  2. 執行命令:java -jar selenium-server-standalone-2.53.0.jar -role hub -hubConfig hub.json

這時再到 Grid Console 頁面檢視,maxSession 引數已經修改成 10.

node 節點Selenium 環境要求

在新增node節點前,我們先關注下,node 節點對環境要求:

1. node 節點必須要有 java 環境
2. node 節點跟hub 節點機器間可以互相 ping 通。(不通時關閉防火牆和安全軟體再試試)
3. node 節點負責執行Selenium 指令碼,所以必須有Selenium 環境(指令碼語言對應的環境如java, 各個瀏覽器及其對應的driver)

新增 node 節點

如果你是跟hub同一臺機器中新增可以直接在控制檯(終端)輸入如下命令:
java -jar selenium-server-standalone-2.53.0.jar -role node

如果你想在別的機器上新增node節點則控制檯(終端)輸入如下命令:
java -jar selenium-server-standalone-2.53.0.jar -role node -hubhttp://192.168.1.110:4444/grid/register

新增完節點後,可以在 Grid Console 頁面上檢視到已經註冊進來的node節點資訊和配置。如下圖:


補充:使用 -role node 登錄檔示這個node節點既可以支援Selenium Remote Control 也支援Webdriver
java -jar selenium-server-standalone-2.53.0.jar -role rc //註冊的節點僅支援Selenium Remote Control
java -jar selenium-server-standalone-2.53.0.jar -role wd //註冊的節點僅支援WebDriver

修改 node 配置

同樣node的配置有兩種方式

通過命令修改

java -jar selenium-server-standalone-2.53.0.jar -role rc -port 6666

通過json檔案修改

例如新建一個node.json檔案,如下記憶體,並放於Grid 同級目錄下

{ "capabilities": [ { "browserName": "chrome", "maxInstances": 5, "platform": "WINDOWS", "version":"51" }, { "browserName": "firefox", "maxInstances": 6, "platform": "WINDOWS", "version":"46.0.1" }, { "browserName": "internet explorer", "maxInstances": 2, "platform": "WINDOWS", "webdriver.ie.driver": "IEDriverServer.exe" } ], "configuration": { "proxy": "org.openqa.grid.selenium.proxy.DefaultRemoteProxy", "maxSession": 5, "port": 5555, "register": true, "registerCycle": 5000, "hub": "http://192.168.84.209:4444" } }

重要引數說明:
"browserName": “chrome"這個很重要,表示你註冊的瀏覽器

"maxInstances": 5這個引數表示最多啟動該瀏覽器的個數

"webdriver.ie.driver": “IEDriverServer.exe”每個瀏覽器driver放置的位置,建議放跟Grid 同級目錄下

執行命令:
java -jar selenium-server-standalone-2.53.0.jar -role node -nodeConfig node.json -hubhttp://192.168.84.209:4444/grid/register

PS:java -Dwebdriver.ie.driver=D:\IEDriverServer.exe -jar selenium-server-standalone-2.37.0.jar -role node -nodeConfig node.json -hub http://127.0.0.1:4444/grid/register ,由於node是可以執行在不通系統上的,所以指定驅動位置-Dwebdriver.ie.driver=D:\IEDriverServer.exe。引數中必須指明-role node才是執行node。

最後檢視Grid Console 頁面,顯示如下node節點資訊:


Paste_Image.png

  到此為止,我們已經配置好Hub 和需要的多個Node 節點,下去我們需要開始編寫測試程式碼

測試程式碼:

在編寫程式碼之前我們先簡單瞭解下兩個工具Maven 和 TestNG。

Maven:是一個專案管理工具,可以用於專案構建打包等,還可以用於專案依賴包管理。
TestNG: 是一個強大的測試框架,設計靈感來源於junit,但優於junit,它提供了很強大的註解,便於我們對case的各種操作。

新建 Maven 工程

我們可以通過IDEA來新建一個Maven 工程,新建過程可以參考http://www.jianshu.com/p/6ca7bbcdf2dd, 並在pom.xml 檔案新增selenium 和 TestNG的依賴包如下:

 <!-- http://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>2.53.0</version>
        </dependency>

        <!-- http://mvnrepository.com/artifact/org.testng/testng -->
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>6.9.10</version>
        </dependency>
    <dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging-api</artifactId>
    <version>1.1</version>
    </dependency>

編寫指令碼

例如我想在遠端的node 節點(192.168.84.19:5555)機器上啟動Chrome/IE/firefox瀏覽器,並開啟百度頁面,這裡我們需要藉助DesiredCapabilities類來指定採用哪個瀏覽器,用RemoteWebDriver 來實現遠端執行,具體程式碼如下:

 //    啟動192.168.84.209:5555 node節點的Chrome
    @Test
    public void testChrome() throws MalformedURLException, InterruptedException {
        DesiredCapabilities chromeDC = DesiredCapabilities.chrome();
        WebDriver driver = new RemoteWebDriver(new URL("http://192.168.84.209:5555/wd/hub"), chromeDC);
        driver.get("http://www.baidu.com");
        Thread.sleep(5000);
        driver.quit();
    }

    //    啟動192.168.84.19:5555 node節點的firefox
    @Test
    public void testFF() throws MalformedURLException, InterruptedException {
        DesiredCapabilities firefoxDC = DesiredCapabilities.firefox();
        WebDriver driver = new RemoteWebDriver(new URL("http://192.168.84.19:5555/wd/hub"), firefoxDC);
        driver.get("http://www.baidu.com");
        Thread.sleep(5000);
        driver.quit();
    }

    //    啟動192.168.84.19:5555 node節點的IE
    @Test
    public void testIE() throws MalformedURLException, InterruptedException {
        DesiredCapabilities ieDC = DesiredCapabilities.internetExplorer();
        WebDriver driver = new RemoteWebDriver(new URL("http://192.168.84.19:5555/wd/hub"), ieDC);
        driver.get("http://www.baidu.com");
        Thread.sleep(5000);
        driver.quit();
    }

補充 DesiredCapabilities類,除了可以指定瀏覽器的名稱還可以指定平臺和瀏覽器版本以及瀏覽器支援的其他功能

  從上面的指令碼我們已經大概知道如果去指定某個指令碼在某個系統和瀏覽器中執行,但是平時我們的case基本上希望的是所有的case可以在期望的平臺和瀏覽器中快速執行,這裡其實有兩個需求,一個是所有的指令碼能都在指定瀏覽器中執行 另一個就是儘可能快速執行。

  先來解決第一個需求:假設現在我有個測試指令碼實現了 ”開啟百度介面,並輸入頁面title“,我希望他可以在A機器(192.168.84.209)上的chrome 瀏覽器 和 firefox瀏覽器執行,在B(192.168.84.19)機器上的IE瀏覽器執行。那麼我們程式碼可以如下設計思路:

1. 通過TestNG 提供的@DataProvider 實現資料驅動(也可以通過.xml做資料來源去實現)
2. 通過不同引數,把指令碼分配到不同的node上的執行

具體實現程式碼如下:

 // 通過TestNG 提供的註解,實現資料驅動
    @DataProvider(name = "data")
    public Object[][] data() {
        return new Object[][]{{"http://192.168.84.209:5555", "chrome"},
                {"http://192.168.84.209:5555", “firefox"},
                {"http://192.168.84.19:5555", "ie"}};
    }

    /**
     * @param nodeURL node 節點的地址
     * @param browser node 節點的瀏覽器
     * @throws MalformedURLException
     */
    @Test(dataProvider = "data") // 獲取對應的資料來源
    public void openBaiduPageTest(String nodeURL, String browser) throws MalformedURLException {
        DesiredCapabilities desiredCapabilities;
//        判斷要開啟的瀏覽器

        if (browser == "chrome") {
            desiredCapabilities = DesiredCapabilities.chrome();
        } else if (browser == "ie") {
            desiredCapabilities = DesiredCapabilities.internetExplorer();
        } else {
            desiredCapabilities = DesiredCapabilities.firefox();
        }

//        拼接處要執行指令碼的node 節點地址
        String url = nodeURL + "/wd/hub";
        WebDriver driver = new RemoteWebDriver(new URL(url), desiredCapabilities);
//        開啟百度
        driver.get("http://www.baidu.com");
        System.out.println(browser + driver.getTitle());
//        關閉瀏覽器
        driver.quit();
    }

需求1解決了,我們再來考慮下需求2:如何儘可能快速執行,畢竟現在大多研發團隊都是走敏捷,如果等你指令碼執行幾小時或者更長時間,那簡直要命。解決思路可以通過並行執行case指令碼來解決。TestNG不僅僅能提供資料驅動的方式,也提供了多種併發方式,這樣就很好解決了我們case並行執行的要求,具體解決如下:

在專案中新建個.xml 檔案,如下

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Default Suite" parallel="methods" thread-count=“3">
  <test name="Selenium_Grid_Demo">
    <classes>
      <class name="com.grid.demo.GridDemo"/>
    </classes>
  </test> <!-- Selenium_Grid_Demo -->
</suite> <!-- Default Suite -->

其中 <suite name="Default Suite" parallel="methods" thread-count="1”> 中的 thread-count 引數值就是併發的程序數,parallel 的引數表示通過哪種方式進行併發可以是 methods , classes , test 。 xml裡面更多的配置有興趣的可以百度瞭解。

例如我的測試GridDemo 類裡面有3個case了,我也新建瞭如上的.xml檔案,那麼我執行該xml檔案會看到這三個case同時執行


執行結果.png

通過Jenkins 執行指令碼

Jenkins 是個CI(持續整合)工具,功能非常強大,外掛也非常多,下面簡單介紹如何把已經編寫好的指令碼放到Jenkins執行。

1. 搭建Jenkins 環境 (百度很多,不詳細說明)
2. 修改本地Maven 專案的pom.xml 檔案,新增如下外掛:
 <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.17</version>
                <configuration>
                    <suiteXmlFiles>
                        <!--要執行的testng的.xml檔案路徑-->
                        <suiteXmlFile>testng.xml</suiteXmlFile>
                    </suiteXmlFiles>
                </configuration>
            </plugin>
        </plugins>
    </build>
1. 開啟Jenkins平臺,新建一個Maven,便可以

Selenium Grid 的GUI管理工具

最後推薦兩個Grid的GUI 管理工具:

1. Jenkins 的Selenium Plugin 外掛,可以在Jenkins外掛中找到

Paste_Image.png

安裝完成後會在導航中新增Grid的入口。


Paste_Image.png
2. VisGrid

下載地址:http://www.codoid.com/products/view/2/30