基于Node.js的UI自动化主流框架

若她涉世未深,就带她看尽人间繁华; 若她心已沧桑,就带她坐旋转木马。

文章尝试对基于Node的主流框架进行一个对比,从而"看尽繁华"。但是对比的指标和权重选取有一定的倾向性。不过,其中各个框架的试用,以及各个指标选取的背后思考还是可以借鉴参考。

1. 为什么是Node.js?而不是Java?

Java的好处:

  • 传统的UI自动化基本就是Selenium为主导了,各种语言的版本都有,但是业内大部分是JAVA系统,所以还是Selenium-Java这一系列为主。
  • 被测系统一般都是Java应用,各种中间件,数据准备API也是Java,便于调用。

 

Node的好处:

  • Javascript对于前端更熟悉了,如果前端自测,无论是单元还是E2E,都更高效。
  • 前后端分离以及基于Node版的中间件模块越来越多,在Node里调用也不是太大问题。
  • 社区和新的框架层出不穷,脚本解释型编写调试效率略高一丢丢。

 

2. 成功入围选手

3. 一言不合就列KPI

重要指标

  • 同步 vs. 异步
  • 多浏览器支持
  • Debug手段(单步调试)
  • API扩展
  • Page Object
  • 语法简洁
  • 用例管理
  • 无线支持

 

权重标准

  • 上面的指标,按照权重自上而下排列。
  • 不过权重大小的标准是主观的,基于和Nightwatch互补,所以目标是同步、支持多浏览器和Debug方便的框架。
  • 你完全可以设定不同的权重得出不同的目标框架。

 

4. 比武招亲正式开始

同步 vs. 异步

因为Node是异步的,所以所有框架原生都是异步的。为了解决callback的噩梦,有Promise等框架可以使得书写更加像同步那样。在这里我们说的同步是说不只是写起来,而是执行也是同步的,就和Java一样。

之所以看重这个指标,是因为:

  • 现实中,其实大部分写UI自动化的人是测试同学。他们对于javascript和异步编程接触很少,对于异步的编写和调试往往呈现不适应,转而排斥Node系列的框架和归纳为UI自动化成本高这样的原因。
  • 很多原有的UI自动化脚本是Java版的,年久失修以后,想拿来修修重用,转成异步发现一脸懵逼了。
  • UI自动化比前端页面写javascript更多的异步逻辑。其实,由于浏览器和自动化脚本是两个进程,webdriver也是问答形式控制浏览器,那么异步编程就是自然而然的事情。相当于一直在和后端通过ajax接口交换数据,但是坏处就是稍复杂一些的用例逻辑,callback噩梦无法避免。

其实本身而言,同步异步只是一个适应的问题,并没有优劣之分。

比较

  • WebdriverIO和Selenium-webdriver都通过插件将异步函数通过队列转化为同步执行管理。

 

WebdriverIO的例子

异步:

    var webdriverio = require('webdriverio');
    var options = { desiredCapabilities: { browserName: 'chrome' } };
    var client = webdriverio.remote(options);

    client
        .init()
        .url('https://www.taobao.com/')
        .setValue('input.search-combobox-input', 'webdriverIO');
        .click('button.btn-search')
        .pause(2000);
        .getTitle().then(function(title) {
            console.log('Title is: ' + title);
        })
        .end();

同步:

    describe('Taobao search', function() {
        it('searches for WebdriverIO', function() {
            browser.windowHandleSize({width: 1024, height: 800});
            browser.url('https://www.taobao.com/');
            browser.setValue('input.search-combobox-input', 'webdriverIO');
            browser.click('button.btn-search');

            browser.pause(3000);
            // 同步的话,我可以变量得到返回值随意进行后续操作,而非callback。
            var title = browser.getTitle();
            console.log('Title is: ' + title);
            //browser.end();
        });
    });

多浏览器支持

在电商的测试环境中,很多时候我们牵涉到多用户的浏览器操作,比如买卖家,助手问答,客服问答,问题双方等等。这时,解决方法有两种:
1. 一种是不断的切换账号达到一个浏览器多个账户的目的,但这显然是比较弱的,执行的观感也会冗余。
2. 另一种是自然的启动两个浏览器,在脚本里对不同的browser方便的做不同操作,必要时候进行同步,达到协作的目的。

比较

评价

虽然号称都支持,但其实支持的方式是不同的,便利程度也不同:

  • Nighwatch是用同一个用例,并发执行用例的方式进行支持,如下面例子展示的一样。执行时通过参数可以决定有哪些浏览器启动,在脚本中通过环境变量进行分别操控,类似多线程编程的感觉。缺点就是整个用例充满了if else,像是硬把两个用例掺杂在了一起,异步再加上这种多线程的编写,给阅读调试都带来不小的难度。
  • WebdriverIO是在配置里配好启动的浏览器名字,脚本里直接使用,因为是同步编程,所以就是按顺序执行了,相对更容易理解多了。
  • 其他的框架都是类似的,driver或者browser是动态创建的,所以脚本里创建多少个就用多少个,也是非常简单直接的。

例子

 

$ nightwatch --env chrome,firefox

脚本

module.exports = new (function() {  
  var firstClient = process.env.__NIGHTWATCH_ENV_KEY == 'chrome_1';
  var testCases = this;

  testCases['opening the browser and navigating to the url'] = function (client) {
    client
      .url('https://simplewebrtc.com/demo.html?nightwatchjs')
      .waitForElementVisible('body', 1000);
  };

  if (firstClient) {
    testCases['wait for clients to become connected'] = function(client) {
      client
        .waitForElementVisible('#localVideo', 1500)
        .waitForClientConnected('#localVideo', 5000)
        .waitForClientConnected('#remotes .videoContainer:nth-child(1) video', 8000,
          'Remote video stream (%s) was connected in %s ms.');
    };

    testCases['wait for peer to disconnect'] = function (client) {
      client
        .pause(1000)
        .waitForElementNotPresent('#remotes video', 10000);
    };
  } else {
    testCases.suspend = function (client) {
      client.pause(10000);
    };
  }

  testCases.after = function(client) {
    client.end();
  };

})();
  • WebdriverIO:
    配置:

    capabilities: {
        myChromeBrowser: {
            desiredCapabilities: {
                browserName: 'chrome'
            }
        },
        myFirefoxBrowser: {
            desiredCapabilities: {
                browserName: 'firefox'
            }
        }        
    },
    

    脚本:

    describe('Taobao search', function() {
    it('searches for WebdriverIO', function() {
        //两个浏览器都进行的操作
        browser.windowHandleSize({width: 1024, height: 800});
        browser.url('https://www.taobao.com/');
    
        // Chrome单独操作,先执行
        myChromeBrowser.setValue('input.search-combobox-input', 'Chrome');
        myChromeBrowser.click('button.btn-search');
    
        // Firefox单独操作,后执行
        myFirefoxBrowser.setValue('input.search-combobox-input', 'Firefox');
        myFirefoxBrowser.click('button.btn-search');
    
        browser.pause(1000);
    
        var title = browser.getTitle();
        console.log('Title is: ' + title);
        // outputs: "Title is: WebdriverIO (Software) at DuckDuckGo"
        browser.end();
    });
    });

Debug支持

异步情况下,对于Debug要求会高一些,最好能够像在IDE中一样单步调试。Node本身有node-inspector可以达到这样的效果,但是往往框架都会有自己的命令行环境,这种情况下,是否还能调用?没有尝试过改造的可行性,但是就从框架本身的介绍来看,我们发现WebdriverIO和Intern是支持的。

比较

例子

在配置里打开debug:true,启动后连接到node-inspector配置的端口即可。但是,如果同步编程的话,其实感觉一般的暂停debugger和log已经基本够用了,单步调试使用的场景不是很多。

API扩展

对于框架来讲,API级别能不能很好的扩展也是挺重要的,最起码我们要扩展一些登录、HSF调用等数据准备的公共函数。当然,因为是开源的,其实都可以修改源码的方式进行扩展,这种就不在此列了。

比较

Page Object

相对于API扩展,更贴合页面的一种抽象层次,复用的好可以减少很多页面元素定位操作的重复劳动。

比较

语法简洁

根本都是基于webdriver的协议,所以语法都类似,但是具体还是有些简洁的差别。从下面例子还是可以看出来,Nightwatch和WebdriverIO比较简洁,Intern是有些繁琐了。

比较

例子

原文例子地址

client
.url('http://google.com')
.setValue('#q', 'webdriver')
.click('#btnG')

Notice how this is far simpler than with the original selenium-webdriverjs,

driver.get('http://www.google.com');
driver.findElement(webdriver.By.id('q')).sendKeys('webdriver');
driver.findElement(webdriver.By.id('btnG')).click();

and significantly simpler than with WD.js:

browser
  .get("http://www.google.com")
  .elementById('q')
  .sendKeys('webdriver')
  .elementById('btnG')
  .click()

and GOD in intern.io:

this.remote
  .get(require.toUrl('http://www.google.com'))
  .findById('q')
    .type('webdriver')
    .end()
  .findById('btnG')
    .click()
    .end()

For more details on the comparison between WebdriverIO, selenium-webdriverjs and WD.js, read this discussion.

用例管理

有很多优秀的测试框架可以和UI自动化框架结合,达到用例管理,结果展示等功能,比如Mocha、Jasmine等。这里是指框架本身已经做了很好的集成,或者本身自己提供了功能。

比较

无线支持

各个框架都是宣称支持webdriver for mobile的协议的,只是支持的API个数不同。如果能够很好支持,那就可以达到一个框架PC和无线通吃的便利性,但实际情况,大家无线还是倾向于专门的Appium等框架去做。

比较

总览

总评

  • Selenium-webdriver和WD.js侧重UI,但封装和功能都比较少。
  • Nightwatch和WebdriverIO各有千秋,社区活跃,友好性都不错。
  • Intern更加侧重全测试方案,覆盖各个测试阶段,单元测试、功能测试等。

 

所以冠军就是

其实还有更多的选择

  • Java型:Selenium-Java
  • 录制型:AUI、Selenium-IDE
  • 图像识别型:Skuli

 

和他们相比又有什么优劣呢?且听下回分解吧。

posted @ 2021-03-09 10:30  小强找BUG  阅读(734)  评论(0编辑  收藏  举报