15 Web 自动化测试 --Selenium Grid + Maven + TestNG + Jenkins 完成Selenium 分布式并发测试

如果你会docker 那么我更推荐你看看:
https://www.jianshu.com/p/29c7240e9f48

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 基本结构

grid结构图.png

  如上图,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管理页面。

Paste_Image.png

点击 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 -hub http://192.168.1.110:4444/grid/register

添加完节点后,可以在 Grid Console 页面上查看到已经注册进来的node节点信息和配置。如下图:

Paste_Image.png

补充:使用 -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文件修改(3.X版本请参考文章末尾配置)

例如新建一个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 -hub http://192.168.84.209:4444/grid/register
最后查看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>

编写脚本

例如我想在远程的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 .equals("chrome")) {
            desiredCapabilities = DesiredCapabilities.chrome();
        } else if (browser .equals( "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

VisGrid.png

补充 (17.07.27更新)

最近因为接手一个项目,又需要重新搭建Grid ,而此时的Webdriver已经是3.x版本了,同时我们看到的Grid的selenium-server-standalone jar包也升级到了3.X 版本,虽然基本用法保持一样,但是在配置Node的json文件时,有点小变动,所以如果你是用3.X版本的Grid那么请参考: https://github.com/SeleniumHQ/selenium/blob/master/java/server/src/org/openqa/grid/common/defaults/DefaultNodeWebDriver.json 中的配置,同时想看Grid的官方帮助请参考: https://github.com/SeleniumHQ/selenium/wiki/Grid2
最后我随手贴出官方给出的默认Node Json配置文件:

{
  "capabilities":
  [
    {
      "browserName": "firefox",
      "maxInstances": 5,
      "seleniumProtocol": "WebDriver"
    },
    {
      "browserName": "chrome",
      "maxInstances": 5,
      "seleniumProtocol": "WebDriver"
    },
    {
      "browserName": "internet explorer",
      "maxInstances": 1,
      "seleniumProtocol": "WebDriver"
    }
  ],
  "proxy": "org.openqa.grid.selenium.proxy.DefaultRemoteProxy",
  "maxSession": 5,
  "port": 5555,
  "register": true,
  "registerCycle": 5000,
  "hub": "http://localhost:4444",
  "nodeStatusCheckTimeout": 5000,
  "nodePolling": 5000,
  "role": "node",
  "unregisterIfStillDownAfter": 60000,
  "downPollingLimit": 2,
  "debug": false,
  "servlets" : [],
  "withoutServlets": [],
  "custom": {}
}

(2018.07.03更新)补充2:
最近偶然查看Selnium 发布的修改log中看到,在Selenium v3.7.0 版本后DesiredCapabilities被迁移到MutableCapabilities或最好使用ImmutableCapabilities 。

https://github.com/SeleniumHQ/selenium/blob/master/java/CHANGELOG

* Migrated from using `DesiredCapabilities` to either
  `MutableCapabilities` or (preferably) `ImmutableCapabilities`.
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容