由于建磊小朋友离职,开始接手比较高大上的分布式模拟器的工作。分布式模拟器关系到团队自动化的执行效率,也关系着测试人力的投入,也算是机遇与挑战并存吧。


2014年4月8日     潜龙勿用


      刚接手的第一天,遇到的第一个问题是由于节假日公司断电,导致模拟器无法执行自动化。当时问题比较棘手,自动化可以说是瘫痪了,等待执行自动化的同学一次次带着希望询问解决的进展,一次次又失望地走回工位。针对这个问题,第一个想到的是交接时提到的,如果机器重启,需要重新配置分布式模拟器的ip。根据这个想法,简单梳理了下分布式模拟器的执行流程,主要是通过两种方式来触发自动化测试:

       第一种是直接在jenkins平台触发自动化测试的job。

       第二种是通过一体化平台调度触发自动化测试job,第二种的执行流程图如下:




wKiom1Qn02njSTfuAAcdtUS5Z-w549.jpg


     step1:首先从一体化测试平台选择测试地址的url信息,经由分布式模拟器的前端服务程序进行调度。

     step2:经由分布式模拟器前端服务执行经由模拟器调度层的轮询操作。

     step3:模拟器调度层会通过RMI的形式与模拟器所在的PC端响应程序通信,返回当前模拟器的使用情况。

     step4:如果有空闲的机器则会继续选择需要测试的类型,例如:FE自测、核心功能测试(Main),非核心功能测试(other)等。

     step5 : 模拟器调度层会根据测试类型的选择,拼接出调度jenkins测试服务的url,以post形式触发jenkins jos。


      在这个过程中需要几个准备工作:

      第一个工作是需要启动nodejs来激活分布式模拟器的前端服务,其次是开启模拟器的响应程序,然后就是执行jenkins提供的slave.jar保持与jenkins服务平台的通信。

      在模拟器调度层,需要配置模拟器所在机器的ip信息,当机器的IP地址改变后,需要手动配置调度层中的IP信息,但是由于调度层是一个client.jar的jar包,每次修改都需要重新打包,这个当然是比较耗时。且在当时同事走得比较仓促,没有把client.jar和server.jar的源码留下,在此又通过XJar将代码反编译后,将配置的IP的信息抽离到配置文件,大体流程弄明白了,问题也迎刃而解。

      这次问题的解决花了大约两个小时的时间,解决过程中发现,如果优先启动slave.jar保证直接触发jenkins的方式可用,就可以保证自动化测试的正常运行。对于交接后流程的快速了解,成为了这几天分布式模拟器工作的重点。攻坚战即将开始。


4月12日-4月16日     履霜,坚冰至


        上一周的主要精力放在了自动化用例编辑平台上,这一周发现大家对分布式模拟器的抱怨越演越烈,关于执行时间长、执行失败甚至无法执行的问题反馈越来越多,为了优先保证自动化测试工作的有效进行,这周主要对模拟器的当前状况进行了摸底,并通读源码,快速了解自动化测试的执行流程。

       看了下jenkins的job执行情况,dailyrun的运行时间的最高纪录达到了7个多小时,平均下来也在5个多小时,测试中常用的核心用例和非核心用例的测试页保持在2.5-3个小时,对于当前的形势,自动化测试已经成为了测试过程中的瓶颈,同时也具有很大的优化潜力。

       兵欲善其事,必现利其器。想要庖丁解牛,首先要对牛具备透彻的了解,对于当前的流程,需要花时间的阅读源码,绘制执行流程图。于是花了半天的时间对自动化的执行流程进行梳理,自动化测试的基本流程图如下:

        

wKioL1Qn07TQk3A4AAVSfF-XWJM766.jpg

      step1:当我们有自动化需求时,会触发对应的jenkins job, 然后会经由jenkins的服务端与节点主机的slave.jar服务进行通信,

从而对自动化测试的流程进行控制,并且对测试的控制台信息进行收集。

       step2:在确认通信已经OK的情况下,slave会受到更新svn的命令,将本次测试所需的代码进行更新。

       step3:更新完毕后,就会执行我们已经写好的executeJob.bat脚本,这个脚本是用来具体操作执行流程的。

       step4:首先会设置环境变量,保证下一步命令的正确运行。

       step5:环境变量设置完毕后,会先后进行自动化Suite的构建工作,例如:ant -buildfile buildAllFunction.xml all。

       step6:在构建的同时,会执行一个sayHi.py的python文件,对模拟器进行相应的操作。

       在这个过程中,由于测试的构建与模拟器的启动同时进行,并且模拟器的启动需要几分钟的时间,会导致第一次进行的自动化测试不能创建WebDriver,导致抛出org.openqa.selenium.remote.UnreachableBrowserException异常,所有case skip后,等待第二轮测试的执行。


        在模拟器的管理中,sayHi.py利用了对UnreachableBrowserException异常的判断,进行了模拟器的启动操作,sayHi.py中主要针对模拟器的生命周期和测试的重跑进行了控制,先上一张模拟器环境的启动流程图:



wKioL1Qn09Tg5lUgAAeioGics3Y503.jpg

        step1:正如上面所说的,刚开始会根据UnreachableBrowserException的异常判断是否已经执行了第一次测试。如果没有的话,会等到testng-results.xml中存在这个异常后,进行模拟器的启动操作。

        step2:开始执行模拟器的启动操作时,优先会kill掉与模拟器相关的几个进程(adb、pcdroid和VBox虚拟机相关的几个进程)。

        step3:启动VBox虚拟机和pcdroid模拟器,获取当前设备的ID后,通过adb对模拟器进行连接。

        step4:这里如果设备没有启动成功,会进行重启操作。(后面发现,由于pcdroid在一定时间内无法启动,导致无限重启的情况。)

        step5:进行端口映射,启动测试所需的程序webDriver,启动定位程序,与模拟器相关的测试环境在这里算是启动完毕了。


        这个过程中,以通过判断异常的方式来启动模拟器服务,在一方面是保证了自动化测试的编译及case生成工作已经准备就绪,避免出现因测试代码问题而导致的重启,但在另一方面也对测试的效率略有影响。与此同时,模拟器环境的稳定性对测试效率的关联性较大,由于模拟器环境会在测试过程中出现卡死或者无响应等情况,因此也对测试的重跑做了以下机制:


wKioL1Qn0-rQzdsMAASPAgvEEjk578.jpg

        step1:在模拟器启动过程中,会使用一个死循环来判断当前模拟器的执行状况以及当前测试的状况。

        step2:通过读取testng-results.xml中skip与fail的数量来判断是否需要重跑。一般来说,测试的case是不允许skip的,因此当发现存在skip的case时,会触发重跑的机制。同时,因为模拟器环境的稳定性问题,可能导致case失败,因此在这里我们的假设是可以通过多次运行case的手段来保证case的正常执行,在这里也就加了一个针对失败用例的重跑规则:如果上一次失败数与本次相同且没有skip的用例,那么我们就认为测试完毕了。

        step3:测试完毕后,需要对测试环境进行还原,并将测试结果发送给本次测试的关注人。


         以上两张图的解析,模拟器的执行流程也就梳理完毕了。接下来是与之并存的自动化执行流程,直接上图:

    

wKiom1Qn09fi2B6nAAJ1NEtQb5c971.jpg

     简单的说就是使用ant对测试代码进行编译和构建,通过读取case的配置文件生成对应的java文件。当编译与打包的工作完毕之后,就进入了自动化的具体执行流程,由于本次主要针对分布式模拟器流程来说,在这里就不对框架的具体流程进行详细论述。在测试中,采用testng这个测试框架,以注解的形式对case的执行流程做了简单归纳,如图:


wKioL1Qn1BSzOdlOAAMaa177etg884.jpg

        BeforeMethod注解主要是执行case运行前的初始化操作。

        Method注解标注的就是我们要执行的用例了。

        AfterMethod是在用例执行完毕后,为了不影响下一个case的测试而清空了当前webdriver对应的session信息。

        通过这三个注解,对测试case的生命周期进行了管理,从而保证了自动化测试的有序运行。



        好了,整体的构造已经被我了解明白了,下面也该当当医生了,看看这个病人的病症到底在哪里。作为一个合格的医生,当然要中西医结合,在对程序一顿望闻问切之后发现,表征很明显,分布地很广,于是就把这周所遇到的表象都记录了下来。

        大体分为四个方面:


        人工干预

        1.PC电脑锁屏,模拟器无法执行,需手动解锁,自动化方可正常运行。

        2.模拟器不能正常启动,导致频繁重启,job无法结束,手动关闭,job执行失败。

    3.运行自动化时,模拟器出现“抱歉,程序意外结束”弹出框,模拟器无法重启,需要人工关闭后可继续运行。

        4.Pcdroid中 VBoxmanage.exe无法启动,出现报错 pcdroid session 被锁定,需要手动重启VBox中pcdroid的虚拟器。

    5.失败次数过多时,生成结果目录名称过长,导致测试结果文件在svn更新前无法自动删除。

    

        稳定性

        1.xml使用testNG.dtd,编译成java过程受dtd规则响应影响,dtd无法访问或延迟,影响自动化功能。(case相关的xml文件已经取出testNG.dtd规则,处理完毕)

        2.在测试中自动化框架可能会命中小流量,导致测试用例失败。(已添加对Monitor小流量的兼容,但是目前不能支持页面元素不同的情况,处理完毕

        3.自动化框架不支持多组数据兼容,增加case可靠性。


        可用性

        1.自动化框架日志输出不够完善,且自动化邮件case info信息不能精确定位问题,通过控制台很难辨别case运行程度。

        2.Pcdroid版本在4.2,不能支持其他版本自动化。


        效率

        1. 运行自动化,模拟器出现白屏,需要等待本轮执行的所有case执行完毕(确切说是skip)后,再会重启模拟器进行验证。

        2. 每次执行通过case过少,导致多次执行,耗时严重。在此做了一次dailyrun中执行自动化case的记录。


        (不包含模拟器测试环境启动与重启的时间)

        第一次:用时 21秒(模拟器没开启,全部skip)

        第二次:用时 57分26秒(第二次执行,仅通过了59个case)

        第三次:用时 8分27秒(模拟器白屏,人工干预1次,关闭模拟器,case没有通过)

        第四次:用时 21分48秒(通过34个)

        第五次:用时14分29秒(模拟器白屏,人工干预1次,关闭模拟器,case通过45个)

        第六次:用时 11分41秒(通过0个)

        第七次:用时 11分41秒(通过0个)

        第八次:用时 11分41秒(通过0个)

        第九次:用时9分26秒(模拟器白屏,人工干预1次,关闭模拟器,发现没有打出monitor监控的log,怀疑通过case未执行,通过0个case)

        第十次:用时8分30秒,通过7个case(由此可得出,白屏后需手动)

        第11次:用时8分9秒,通过0个case

        第12次:用时46秒(不能忍了,白屏了N久,手动关闭模拟器,通过case 0个)

        第13次:用时6分59秒(远程登录PC机器导致模拟器运行出错,通过40个)

        第14次 全部skip

        第16-25次,分别耗时1分17秒,一直是系统找不到制定路径,运行0个case

        第26次,耗时6分30秒,完成83个case,daliyrun执行完毕。

        本次case在多次人工干预的情况下仍然以耗时5小时6分钟结束。




    4月19日-4月23日 见龙在田,利见大人


        鉴于以上几个方面,该如何对症下药,还需要进一步的化验,那就验个血、做个B超什么的,看看到底症结在哪里。由于上周一直在处理分布式模拟器方面的问题,用例编辑平台进展较为缓慢,本周准备把主要精力放在用例编辑平台的工作上,可是因为与爽姐的沟通改变了计划。

    当我把当前模拟器的问题跟爽姐看了之后,得到的反馈是白屏问题已经是自动化测试的当务之急,需要通过技术手段予以解决。进行了一番交流后,大体头脑风暴了以下几种方案:

        第一种,卸载并重装webdriver,处理的比较彻底,属于宁可错杀一千,不可放过一个的类型,因为无法获取case的运行状态而pass。

        第二种,首先,保存最后一个执行成功case的id和上一个case的id。

        其次,在init时判断上一个case的id和最后一个执行成功id是否一致,如果不一致说明上一个case出现了错误(防止skip的错误验证,skip时只会执行teardown方法)。

        然后,调用脚本卸载webdriver。

        最后,重新执行skip的用例。


        第三种,在log中进行打点,经由判断控制台日志来验证webdriver执行状态,从而进行卸载重装操作。

       这种方法个人感觉可能会麻烦一些,因为可能涉及到多次白屏,每次白屏判断之后需要把指针设置到上一次白屏日志之后,然后再进行判断。同时如果监控日志的话,也需要在case执行的周期中做判断或者增加监控线程,在实现难度上感觉会比直接用逻辑判断要大,pass。


        感觉第二种方案比较靠谱,于是就根据第二种方案的思路进行实施。于是,我抱着这种态度对自动化框架进行了打点。打点的目的主要针对两个问题:第一个是判断这个case已经正确执行。第二个是判断没有正确执行的case因为什么原因没有执行。

        分别针对 进入BeforeMethod(打点为1),执行webdriver、selenium初始化(打点为2),加载元素配置(打点为3)、BeforeMethod结束(打点为4)、开始执行Method(打点为5)、执行完毕Method(打点为6) 进行了打点,然后在程序中输出出来,执行jenkins job,开始观察。


        最后发现出现两种比较反常的情况,一种是,在4停留的时间过长,一直没有进行5的操作。一种是,在5执行时间过长,没有6的操作就调用了AfterMethod。鉴于这两种情况触发场景进行了还原,发现是因为webdriver挂起导致case无法运行的问题。(额。。。在init中验证是否为白屏,如果白屏就重启模拟器,方案貌似可行,结果在执行时发现在init中无法判断白屏问题。


wKioL1Qn1C3BiHRoAAcM0XfRggk087.jpg


        接下来就针对当前症结对症下药,为了解决第一个问题,在自动化框架初始化过程供增加了一个对执行状态的监控线程,发现一旦在4停留时间过长,那么我们就认为webdriver异常了,执行重启Webdriver操作,此问题KO。第二种问题的捕获点在AfterMethod中触发,一旦发现进入该方法时仍为5状态,我们就可以断定case没有按照我们的预期完成,标志异常,执行重启webDriver操作,这个也KO。在经过多次调试后,这个影响效率的大毒瘤终于被解决掉了。上一张dailyrun的执行效率图。


wKiom1Qn1CTQOV5nAAFgVdTHWuc854.jpg

    在这里也感谢使用分布式模拟器的同事们,你们的每一次认可都会成为我继续优化的动力。同时希望分布式模拟器能够带来更多的价值,优化我们的测试流程,让WebAppQAs的工作更加高效!