————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个测试模式要求如下:
不同版本对应的mini软件状态要求如下:
REPRODUCING PROCEDURES:
目前这个apk,整体架构比较简单,而且耦合性太高,代码有很多冗余, 格式不规范。其整体架构如下图所示:
在整个架构中多用的继承,使得各个case之间其实耦合性很大,而且扩展性不强。因此期望重构过程中多用组合,少用继承,使系统更具弹性。
EXPECTED
代码精简&&语法规范&&架构重构
框架部分主要有如下几个Activity:
整个软件的入口Activity是MiNiActivity,业务流程如下图所示:
通过MiNiActivity来判断用户使用哪种测试方式执行测试,而实际的测试项是在ExecuteTestActivity中完成的。
根据自动测试模式和手动测试模式的不同情况,通过使用观察者模式的思想来设计自动测试模式,使用策略模式的思想来设计手动测试模式。
自动测试的设计流程如下所示
手动测试的设计流程如下所示
在这个测试软件重构过程中,期望把测试的框架和测试的具体case分离开来,这样在以后的维护中可以分开维护,即如果需要增加、修改、删除某些测试case时,其他的case完全不受到影响,而且整个软件框架不需要去改动。对应的架构如下图所示:
测试实际的Activity(在项目中是ExecuteTestActivity.java)并不需要改变,只需要替换不同的测试内容(在项目中表现为继承了Test.java的子类),就可以达到显示不同的测试case的目的。对于很多case中界面部分逻辑,将它分离出来作为一个单独的工具类(还有一些其他的工具类,如控制计时器的类、部分控件监听器等),当有需要用到它时,它将作为具体测试内容的一个属性被使用。
本测试软件的设计是希望能够适用于不同项目的设备,而不同设备所具备的测试项是具有一定的差别的,所以mini软件中通过读取设备自身系统值来区分需要包含的case。
首先,将所有的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" />
子元素deviceNode存储设备中各个驱动节点的信息,主要包括节点绝对路径和对应的变量名,其结构如下:
<deviceNode name="FrontCameraNode" path="/sys/class/deviceinfo/device_info/CamNameF" />
因为各个项目设备的驱动节点路径可能不同,将它从java代码中分离出来方便维护,在导入mini软件时,根据设备实际情况配置好各个驱动节点的路径即可。
配置项目自己的xml文件
./assets/Base.xml
文件存储了所有可能用到的case信息,但是针对具体项目,可能只是需要部分的测试case,所以通过项目自己的xml文件来进行调整。
如./assets/Base.xml
中记录了如下case:
现有project_A
和project_B
2个项目,然后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的调整。
将最终的测试项信息存储在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中。
因为所有的测试项都是继承共同的基类Test.java,所以各个测试项将作为执行Activity(ExecuteTestActivity)的属性,通过执行Activity的生命周期创建出来,其效果如下图所示。
Test.java具体代码如下所示:
其实Test.java就是根据Activity组件,创建了相对于它生命周期的方法,但是大部分方法都是空实现,而具体逻辑则是由继承Test.java的子类来实现。
ExecuteTestActivity.java的实现如下所示:
在ExecuteTestActivity中,通过getCurrentTest
方法获取测试case对应的Test类对象(如前面描述的A.java、B.java对象),然后通过适配器模式,将具体case的逻辑通过ExecuteTestActivity生命周期展示出来。
在整个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_RETURN
且resultCode=Test.RESULT.PASS
,进入步骤六,测试项的index++,并将它作为参数传入目标Activity。
如果requestCode=Test.TEST_RETURN
且resultCode=Test.RESULT.FAIL
,进入步骤九。
如果requestCode=Test.TEST_RETURN
且resultCode=Test.RESULT.INTERRUPT
,进入步骤八。
如果requestCode=Test.FAIL_RETURN
且resultCode=Test.RESULT.RETEST
,进入进入步骤六,测试项的index依旧保持原来的值,然后将它作为参数传入目标Activity。
如果requestCode=Test.FAIL_RETURN
且resultCode=Test.RESULT.NO
,将测试失败的结果保存到mLastTestResult中。
如果requestCode=Test.FAIL_RETURN
且resultCode=Test.Test.RESULT.NEXT
,进入步骤六,测试项的index++,并将它作为参数传入目标Activity。
如果requestCode=Test.RESULT_RETURN
且resultCode=Test.RESULT.YES
,进入步骤五。
如果requestCode=Test.INTERRUPT_RETURN且resultCode=Test.RESULT.RETEST,进入进入步骤六,测试项的index依旧保持原来的值,然后将它作为参数传入目标Activity。
如果requestCode=Test.INTERRUPT_RETURN
且resultCode=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软件仍然有很多不足的地方,需要后面继续对其进行优化。
手机扫一扫
移动阅读更方便
你可能感兴趣的文章