zoukankan      html  css  js  c++  java
  • 基于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({ 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({ 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

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

  • 相关阅读:
    菜吉の骗分导论
    P3527 [POI2011]MET-Meteors 整体二分
    整体二分
    P5459 [BJOI2016]回转寿司 cdq分治
    P3810 【模板】三维偏序(陌上花开) cdq分治
    cdq分治:从归并到cdq套cdq
    KDtree 详解
    查看.a和so文件接口
    机器学习 ONNX Model Zoo
    剖析依赖属性
  • 原文地址:https://www.cnblogs.com/zgq123456/p/14504147.html
Copyright © 2011-2022 走看看