MINItest软件架构总结
阅读原文时间:2023年07月08日阅读:3

MINItest软件架构总结

————helloWen


MINItest软件架构总结
1. Problem Description
2. Analysis
3. Solution
3.1. 通过读取设备信息来确定测试项信息
3.2 将测试项通过Activity加载并显示出来
3.3 控制各个Activity之间跳转
4. Summary

  • Precondition:

    手机在试产过程中需要确认生产的机器硬件是否正常,而MINI软件就是这样一个测试手机硬件基本功能是否正常的精简系统(实际上就是一个内部测试软件)。MINI软件是提供给工厂用来测试硬件是否正常工作(如摄像头是否正常拍照,触摸屏是否灵敏等)的测试软件,它是包含MINI APK(也可叫做MMI)的最精简系统版本软件,贯穿手机整个生产流程,对生产非常重要。

    MINI测试软件的主要是包含“AUTO”测试和“MANU”测试,这些测试的规范都由NPI部门主导完成,MINI测试设计要严格按NPI的规范进行设计,这2个测试模式要求如下:

    • 自动测试模式,按照一定的顺序依次执行各个测试项,一旦有一个测试项FAIL,则中断测试,适用于工厂自动化对所有测试项进行测试。
    • 手动测试模式,所有测试项都显示在手动测试列表中,可任意选择测试项进行测试,适用于对单个测试项进行测试。

    不同版本对应的mini软件状态要求如下:

    • 在MINI软件的状态下,手机开机完成就会自动进入到MMI软件测试的界面。
    • 在客户化软件的情况下,我们通过在拨号界面输入暗码可以进入到MMI软件测试的界面。
  • REPRODUCING PROCEDURES:

    目前这个apk,整体架构比较简单,而且耦合性太高,代码有很多冗余, 格式不规范。其整体架构如下图所示:

    在整个架构中多用的继承,使得各个case之间其实耦合性很大,而且扩展性不强。因此期望重构过程中多用组合,少用继承,使系统更具弹性。

  • EXPECTED

    代码精简&&语法规范&&架构重构

框架部分主要有如下几个Activity:

  • MiniActivity,主界面 activity,可选择2中测试方式,其一,是自动测试(即按着配置文件顺序测试完一项后紧接下一项继续测试);其二,手动测试(用户根据自己选择测试某个单独项)。
  • FailedActivity,自动测试失败后,可以选择退出自动测试、忽略错误继续下一项测、重新测试当前项等3个选项。
  • ManuListActivity ,当点击手动测试,显示试列表界面。
  • ResultActivity ,自动测试完毕后,显示测试结果。
  • ExecuteTestActivity ,执行测试项界面,所有测试项执行时均在此activity执行。
  • InterruptActivity ,中断activity,当在测试界面时,可以通过长按Back键进入该界面。

整个软件的入口Activity是MiNiActivity,业务流程如下图所示:

通过MiNiActivity来判断用户使用哪种测试方式执行测试,而实际的测试项是在ExecuteTestActivity中完成的。

根据自动测试模式和手动测试模式的不同情况,通过使用观察者模式的思想来设计自动测试模式,使用策略模式的思想来设计手动测试模式。

  • 自动测试的设计流程如下所示

  • 手动测试的设计流程如下所示

  • 在这个测试软件重构过程中,期望把测试的框架和测试的具体case分离开来,这样在以后的维护中可以分开维护,即如果需要增加、修改、删除某些测试case时,其他的case完全不受到影响,而且整个软件框架不需要去改动。对应的架构如下图所示:

  • 测试实际的Activity(在项目中是ExecuteTestActivity.java)并不需要改变,只需要替换不同的测试内容(在项目中表现为继承了Test.java的子类),就可以达到显示不同的测试case的目的。对于很多case中界面部分逻辑,将它分离出来作为一个单独的工具类(还有一些其他的工具类,如控制计时器的类、部分控件监听器等),当有需要用到它时,它将作为具体测试内容的一个属性被使用。

  • 本测试软件的设计是希望能够适用于不同项目的设备,而不同设备所具备的测试项是具有一定的差别的,所以mini软件中通过读取设备自身系统值来区分需要包含的case。

3.1. 通过读取设备信息来确定测试项信息

  1. 首先,将所有的case信息写入到./assets/Base.xml文件中,而Base.xml的结构如下所示:

    子元素macro存储各个case的详细信息,主要包括case的全限定名、是否加入auto测试、是否在eng中显示、显示名、是否在mini版中显示等信息,其结构如下:

    <macro name="com.jrdcom.mmitest.test.TraceabilityTest" auto="true" eng="true" listName="TRACEABILITY" mini="true" />

    • name: 表示该测试项的全限定名。
    • listName: 表示该测试项在MANU的list列表中显示的名字。
    • eng:true表示在eng版本出现该测试项,false表示不出现。
    • mini:true表示在mini版本中出现该测试项,false表示不出现。
    • auto:true表示在AUTO模式出现该测试项,false表示不出现。

    子元素deviceNode存储设备中各个驱动节点的信息,主要包括节点绝对路径和对应的变量名,其结构如下:

    <deviceNode name="FrontCameraNode" path="/sys/class/deviceinfo/device_info/CamNameF" />

    • name: 表示该驱动节点变量名。
    • path: 表示该驱动节点绝对路径。

    因为各个项目设备的驱动节点路径可能不同,将它从java代码中分离出来方便维护,在导入mini软件时,根据设备实际情况配置好各个驱动节点的路径即可。

  2. 配置项目自己的xml文件

    ./assets/Base.xml文件存储了所有可能用到的case信息,但是针对具体项目,可能只是需要部分的测试case,所以通过项目自己的xml文件来进行调整。

    ./assets/Base.xml中记录了如下case:

    现有project_Aproject_B2个项目,然后project_A需要测试项A、B、D(只在自动测试模式出现)、E4个case,而project_B需要测试项A(在mini测试模式不出现)、B、C(在自动测试模式不出现)、D、E5个case,则需要在project_A项目设备上创建 ./assets/[ro.product.device].xml文件,其文件内容如下:

    project_B项目设备上创建 ./assets/[ro.product.device].xml文件,其文件内容如下:

    即项目自己的xml文件优先级高于./assets/Base.xml优先级,对于相同的macro节点,项目的macro会覆盖./assets/Base.xml中的macro,从而实现对各个case的调整。

  3. 将最终的测试项信息存储在ArrayList中

    • 首先,分别读取./assets/Base.xml中macro节点信息和./assets/[ro.product.device].xml文件中macro节点信息,并将macro节点信息存储在PullXmlParser对象的List<DeviceNode> mDeviceNodeList属性中

    • 然后,合并./assets/Base.xml中macro节点信息和./assets/[ro.product.device].xml文件中macro节点信息。

    • 最后,将最终的测试项信息存储在DeviceNodeList类的静态变量deviceNodeList中。

3.2 将测试项通过Activity加载并显示出来

因为所有的测试项都是继承共同的基类Test.java,所以各个测试项将作为执行Activity(ExecuteTestActivity)的属性,通过执行Activity的生命周期创建出来,其效果如下图所示。

Test.java具体代码如下所示:

其实Test.java就是根据Activity组件,创建了相对于它生命周期的方法,但是大部分方法都是空实现,而具体逻辑则是由继承Test.java的子类来实现。

ExecuteTestActivity.java的实现如下所示:

在ExecuteTestActivity中,通过getCurrentTest方法获取测试case对应的Test类对象(如前面描述的A.java、B.java对象),然后通过适配器模式,将具体case的逻辑通过ExecuteTestActivity生命周期展示出来。

3.3 控制各个Activity之间跳转

在整个mini软件中,MiniActivity作为核心的Activity在软件的运行过程中一直存在,由它控制各个Activity之间的跳转,具体情况如下:

  • 步骤一: 在进入mini软件后,会显示主界面MiniActivity,在该界面用户可以选择Auto测试和Manu测试,如果点击Auto测试,则进入步骤四;如果点击Manu测试,则进入步骤二。

  • 步骤二: 进入ManuListActivity界面,并显示所有eng=ture的macro节点的case,系统可根据用户点击的case项进入步骤三。

  • 步骤三: 开启ExecuteTestActivity,并且根据用户点击的case项,实例化对应的Test对象,将该对象作为参数传入ExecuteTestActivity中运行。

  • 步骤四: 判断ArrayList类型属性值mLastTestResult是否为空(每次Auto测试结束都会将测试失败结果保存到mLastTestResult中,默认第一次开机情况和上次测试全部通过情况mLastTestResult值为空),如果为空,进入步骤五,否则进入步骤

  • 步骤五: 跳转到ExecuteTestActivity中,并设置requestCode=Test.TEST_RETURN,将测试项的index作为参数传入ExecuteTestActivity中(第一次进入,默认测试项的index值为0),然后进入步骤六

  • 步骤六: 首先,启动ExecuteTestActivity,并且将传入的参数通过getCurrentTest方法构造出将要测试case的Test对象,然后通过ExecuteTestActivity将构造出的Test对象展示出来,最后根据用户的点击事件进行返回:

    如果用户点击pass按钮,则finish掉ExecuteTestActivity,并设置resultCode=Test.RESULT.PASS然后进入步骤七;

    如果用户点击fail按钮,则则finish掉ExecuteTestActivity,并设置resultCode=Test.RESULT.FAIL然后进入步骤七。

  • 步骤七: 回到MiniActivity中,根据resultCode和requestCode值进行跳转:

    如果requestCode=Test.TEST_RETURNresultCode=Test.RESULT.PASS,进入步骤六,测试项的index++,并将它作为参数传入目标Activity。

    如果requestCode=Test.TEST_RETURNresultCode=Test.RESULT.FAIL,进入步骤九。

    如果requestCode=Test.TEST_RETURNresultCode=Test.RESULT.INTERRUPT,进入步骤八。

    如果requestCode=Test.FAIL_RETURNresultCode=Test.RESULT.RETEST,进入进入步骤六,测试项的index依旧保持原来的值,然后将它作为参数传入目标Activity。

    如果requestCode=Test.FAIL_RETURNresultCode=Test.RESULT.NO,将测试失败的结果保存到mLastTestResult中。

    如果requestCode=Test.FAIL_RETURNresultCode=Test.Test.RESULT.NEXT,进入步骤六,测试项的index++,并将它作为参数传入目标Activity。

    如果requestCode=Test.RESULT_RETURNresultCode=Test.RESULT.YES,进入步骤五。

    如果requestCode=Test.INTERRUPT_RETURN且resultCode=Test.RESULT.RETEST,进入进入步骤六,测试项的index依旧保持原来的值,然后将它作为参数传入目标Activity。

    如果requestCode=Test.INTERRUPT_RETURNresultCode=Test.RESULT.FAIL,进入步骤九。

  • 步骤八: 设置requestCode=Test.INTERRUPT_RETURN,并启动InterruptActivity,然后根据用户点击事件进行跳转:

    如果点击RETEST按钮,则finish掉InterruptActivity,并设置resultCode=Test.RESULT.RETEST然后进入步骤七。

    如果点击FAIL按钮,则finish掉InterruptActivity,并设置resultCode=Test.RESULT.FAIL然后进入步骤七。

  • 步骤九: 设置requestCode=Test.FAIL_RETURN,并启动 FailedActivity,然后根据用户点击事件进行跳转:

    如果点击RETEST按钮,则finish掉FailedActivity,并设置resultCode=Test.RESULT.RETEST然后进入步骤七。

    如果点击NO按钮,则finish掉FailedActivity,并设置resultCode=Test.RESULT.NO然后进入步骤七。

    如果点击NEXT按钮,则finish掉FailedActivity,并设置resultCode=Test.RESULT.NEXT然后进入步骤七。

MiniActivity中Activity跳转设计如下所示:

本次主要是对重构后mini软件进行总结,相对与前面一个本版,主要是对框架和具体测试case进行了分离,这样软件框架和具体测试case可以分开维护,即维护框架的人员只需要关注框架本身而不用了解具体测试case的内部逻辑,维护具体测试case人员只要知道框架提供的接口,就可以开发出和框架兼容的测试case。并在新的框架中使用了多种设计模式,优化了代码结构,类继承最多只到3层,更多的使用组合模式来连接不同的逻辑模块,相较前面的版本,可扩展性也有了较大的提高。但是发现重构后mini软件仍然有很多不足的地方,需要后面继续对其进行优化。

null