zoukankan      html  css  js  c++  java
  • 【转】应用宝基于Robotium自动化测试

    (转载:http://tmq.qq.com/2016/05/robotium_for_app_test/)

    1 背景目的
    应用宝项目组采用FT(Feature Team)模式,整个项目组分为多个FT,而每个FT又同时有多个需求分支在并行运作着,几乎每天都有多新特性合入主干,项目节奏快、变更频繁,且又希望能够短周期内快速地对外发布新版本,做到快速交付、持续交付。
    为了支撑项目组的这种研发模式,测试侧需要在FT分支上及主干上做大量的测试,而其中在FT分支的rebase测试、合流后验证、主干灰度测试等等阶段还包括大量的重复性测试,因此有必要在这些环节加入自动化测试,以持续验证新特性未破坏原有系统。

    2 框架选择

    如表1所示,对比了目前业界常用的几个可用于Android端的自动化测试框架:

    表1 Android自动化测试框架对比
    框架对比
     

    通过对比可以发现不同的测试框架各有优缺点,且基本都不能独自满足所有的测试场景,正所谓菜刀、牛刀、剪刀、指甲刀,刀刀皆有自己的用途与适用场景,我们需要根据项目情况及实际的使用场景来选择最适用的工具。Robotium基于原生Android Instrumentation扩展而来,因此基于Robotium的测试既可以使用Robotium本身的API,还可以使用Android原生的丰富API,可扩展性更强,且基于Robotium的测试在执行速度、稳定性上有一定优势,而应用宝在手机端只有Android版本,也没有跨平台的需求,综合考虑,因此选择了Robotium框架。

    3 环境搭建
    3.1 基础环境搭建
    测试工程使用了Robotium,采用了的是Android Junit工程,因此需要搭建基础的Android开发环境,包含JDK、Android SDK、Eclipse + ADT插件 + SVN插件等等开发工具,具体可搜“Android开发环境搭建”搭建基础环境。
    3.2 导入测试工程
    1.使用Eclipse导入项目
    2.配置Build Path
    3.配置keystore
    在实际项目中,如果是自家的项目,显然是不希望对被测App进行重签名的,有如下原因:
    1)每日进行测试的包众多,一一进行重签名影响效率
    2)如微信、应用宝等应用做了签名防护措施,重签名后将导致应用部分功能不可用甚至直接无法启动
    测试工程需要与被测工程签名一致,因此测试工程需要将keystore配置成应用宝的签名。Window——Preferences——Android——Build,如图1所示,点击Browser,选择应用宝的debug.keystore签名,配置完成后,用Eclipse调试时,测试工程打出的apk即是应用宝的签名了,可以测试应用宝对外发布的任何包。

    图1
    图1 Eclipse中配置自定义签名

    4.配置编码
    新导入工程后,工程可能有许多红点,此时工程任意有注释的java文件,如果注释为乱码则是因为编码不一致导致。此时需要将工程编码设置为utf-8。也可右键选择测试工程,仅设置该工程为UTF-8编码。
    3.3 Eclipse设置
    工欲善其事,必先利其器,测试工程使用Eclipse作为IDE,而为了编写代码可以更高效,有必要进行一些提高效率的设置。
    1.配置输入联想
    为了提高测试用例的代码编写效率,很有必要配置输入联想,在Eclipse中Preferences——Java——Editor——Content Assist配置输入联想

    图2
    图2 Eclipse中配置代码自动提示

    其中Auto activation triggers for java中默认只有.符号,即输入.时才会有代码联想出来,为了充分利用代码联想功能,需要在该输入框中把abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ这26个字母及.号输进去,这样,当键入.号或26个字母时,就会有自动提示,提高代码输入效率。
    2.配置Eclipse的JVM参数
    Eclipse的JVM默认设置参数较小,因此可能造成各种卡慢现像,而我们的开发机配置一般较高,可以通过调整JVM参数充分利用机器资源提高Eclipse运行的流畅度,修改Eclipse安装目录下的eclipse.ini文件即可,具体可参考如下配置(修改-vmargs参数后面的配置):
    -vmargs
    -Dosgi.requiredJavaVersion=1.6
    -Xms2048M
    -Xmx2048M
    -Xmn656M
    -XX:PermSize=512M
    -XX:MaxPermSize=1024M
    -XX:+UseParallelGC
    -XX:CMSInitiatingOccupancyFraction=85
    -Xverify:none
    -Xnoclassgc
    -XX:+CMSClassUnloadingEnabled
    -XX:+CMSPermGenSweepingEnabled
    -XX:+DisableExplicitGC
    3.关联源码
    a)关联内引用jar包的源码
    导入测试工程后,libs下的Robotium和Uiautomator两个jar使用了properties配置,默认就已关联上了sources目录下的源码,如图3所示:

    图3
    图3 Eclipse中配置关联private jar

    b)关联外引用jar包的源码
    关联外引用jar包的源码,这里主要关联Android SDK中的源码,右键android.jar,进入Java Source Attachment选项,关联sdk中的源码,如图4所示:

    图4
    图4 Eclipse中配置关联外引用的jar

    至此,不论进入的是Android SDK还是Robotium中的class类,均可以查看到其源码实现。
    4 Robotium
    4.1 Robotium介绍
    Robotium对外主要提供以下几个类:

    	By:								//Web元素的选择器
    	Condition:						//接口类,用于等待
    	RobotiumUtils:					//工具类
    	Solo:							//对外提供各种API
    	Solo.Config:					//Solo配置类
    	SystemUtils:					//系统级工具类
    	TimeOut:						//Solo配置类
    	WebElement:						//Web元素的抽象类

    其中Solo类是主要对外提供各种API的类,Solo类采用中介者模式,持有com.robotium.solo包下的其它类的的实例对象,当我们调用Solo类中的API时,实则大多数是转而调用com.robotium.solo包下其它类的方法。com.robotium.solo包下主要有以下类:

    	Getter:							//提供控件获取相关API
    	ActivityUtils:					//提供Activity相关API
    	Asserter:						//提供断言相关的API
    	Clicker:						//提供模拟点击相关的API
    	ScreenshotTaker:				//提供截图相关的API
    	Scroller:						//提供滚动相关的API
    	Searcher:						//提供控件搜索相关的API
    	ViewFetcher:					//提供控件过滤相关的API
    	Waiter:							//提供控件等待相关的API
    	WebUtils:						//提供Web支持相关的API

    Robotium为了简化测试用例的编写,将以上的这些类都置为了protected,对外只提供Solo类,因此,在编写测试用例时,主要实例化Solo类即可
    Robotium为一款支持黑盒测试也支持白盒测试的自动化测试框架,简单易用,提供了获取控件、发送点击事件、断言等等API。
    主要API如表2所示:

    表2 Robotium主要API
    Robotium主要API

    通过如上API文档也可以发现,Robotium框架提供的API是有限的,且也只是使用了一小部分Android的API封装而成。使用Android、Java丰富的类库我们可以开发出微信、手Q、应用宝等等众多App,同样地,我们也可以使用这些丰富的类库去扩展测试框架。
    因此,选择Robotium测试框架,不只是选择的一个测试框架,而是选择的一种测试模式,即基于Android、基于Junit的测试模式。
    4.2 Native控件获取与处理
    1.uiautomatorviewer
    可以使用%ANDROID_HOME% ools目录下的uiautomatorviewer.bat工具直接获取当前界面的控件结构及其id。
    注:uiautomatorviewer只有在Android较高版本(4.3及以上)才能直接获取控件id值。

    图5
    图5 Uiautomatorviewer查看控件

    2.处理唯一id的控件
    如果当前界面该控件id是唯一的,则处理起来很简单,如下:
    Button loginBtn = (Button) solo.getView(“loginBtn”);
    solo.clickOnView(loginBtn)

    3.处理id相同的控件
    在Android中,列表ListView采用的是Adapter形式,所以列表中的控件id都是相同的。
    此时,需要先获取节点控件的父视图,通过父视图再查找相应的子视图。

    4.控件过滤
    测试过程中最常见的方式就是控件过滤
    API:getCurrentViews(Class classToFilterBy, View parent)
    例如想获取某一个区域内的所有文本:
    ArrayList textViews = holo.getCurrentViews(TextView.class,parentView);
    其中parentView为父视图,获取parentView下所有的TextView

    4.3 WebView控件获取与处理
    WebElement元素获取可以通过Chrome Mobile Emulation模式获取。安装有较新版本Chrome浏览器,按F12即可进入Chrome Mobile Emulation模式。
    输入H5页面链接,如:http://xxx.xxx.xxx/index.html

    图6
    图6 Chrome按F12

    如图6所示可以看到’电视剧’拥有class=”classify classify-tv”的唯一属性。
    对于有些无法通过PC浏览器打开的H5页面,可以通过Chrome DevTools连接手机端直接进行调试。
    使用DevTools需要以下前置条件:
    1.PC端需要安装Chrome 32及以上版本
    2.USB线连接手机设备
    3.用于browser debugging:需要Android4.0及以上版本,并安装有Chrome Android版本
    4.用于app debugging:需要Android4.4及以上版本,并将WebView设置为可调试
    需要注意的是,PC端中的Chrome版本需要高于手机端中的Chrome版本。
    App中将WebView设置为可调试,可使用如下代码设置:
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    WebView.setWebContentsDebuggingEnabled(true);
    }
    DevTools详情介绍可参见官网:
    https://developer.chrome.com/devtools/docs/remote-debugging#reverse-port-forwarding
    然后,在Chrome浏览器地址栏中输入“chrome://inspect/#devices”
    打开应用宝,进入含有WebView的页面,例如进入娱乐TAB,如图7所示,可以看到出现了可以inspect的页面,点击’inspect‘按钮即可对该页面进行调试,如图8所示,展示了该页面的元素。

    图7
    图7 Chrome中使用DevTools
    图8
    图8 DevTools 点击inspect后展示页面元素

    知道了元素的属性后,即可调用相应API获取WebElement对象,通过By方式获取:getCurrentTxWebElements(By by);By方式支持通过classname、id、textcontent等方式,如:
    holo.getCurrentTxWebElements(By.className(className));
    获取到了相应的WebElement对象后,即可对Web元素进行操作:
    clickOnWebElement(By by)
    clickOnWebElement(WebElement webElement)
    waitForTxWebElement(By by,int timeout,boolean scroll)
    4.4 断言
    1.Assert中的断言
    使用junit.framework.Assert包中的断言:断言条件的true或false、是否为空等等。如图9所示:

    图9
    图9 Assert中的断言

    2.ViewAsserts中的断言
    使用android.test.ViewAsserts包中的断言:包括断言控件是否左对齐、右对齐、父视图是否包含某子视图等等。

    图10
    图10 ViewAsserts中的断言

    5 跨应用(结合UiAutomator2.0)
    2015年3月Android Developers团队宣布了UiAutomator 2.0版本的发布,这个版本最重要的就是UiAutomator终于可以基于Instrumentation了,使用Instrumentation test runner即可运行UiAutomator,反过来,也即在基于Instrumentation的test中也能使用UiAutomator。因此测试工程可同时使用Robotium和UiAutomator进行更丰富地测试。
    新版的UiAutomator随Android Support Repository发布,可通过SDK Manager下载,以2.1.0版本为例,位于如下所示的路径中:
    %ANDROID_HOME%extrasandroidm2repositorycomandroidsupport estuiautomatoruiautomator-v182.1.0
    新的测试支持库基本都是基于Android Studio库,文件以aar结尾而非jar结尾,本小节为方便在Eclipse中介绍需要将aar转化成jar。如图11所示,使用压缩工具打开uiautomator-v18-2.1.0.aar文件,里面的classes.jar文件即是可用于Eclipse的UiAutomator jar包。提取出该classes.jar文件并重命名为方便记忆的jar包文件,导入至使用了Robotium的测试工程即可。

    图11
    图11 解压aar文件

    如图12所示,应用宝在通知栏中开启了快捷工具栏,测试此功能时需要开启通知栏,并点击工具栏中的按钮,这样的操作仅通过Robotium框架是无法完成的,此时就可以结合UiAutomator来实现。

    图12
    图12 应用宝快捷工具栏

    UiAutomator发布2.0版本后,可以通过传入Instrumentation对象获得UiDevice对象。
    UiDevice.getInstance(instrumentation);通过UiDevice对象可以完成点击Home键、打开通知栏,并通过UiDevice的findObject方法可以根据文本、资源id等等查找控件,并通过UiObject对象完成点击操作。
    使用的findObject方法得到的为UiObject对象,此外也可以通过By的方式获取UiAutomator中的UiObject2对象,例如:
    uiDevice.findObject(By.res(“com.tencent.android.qqdownloader”, “entry_text_1”)).click();
    UiAutomator2.0还有许多更丰富更强大的功能,这里就不再一一介绍,总之,通过与Instrumentation结合可以方便地在测试工程中完成跨应用的操作,进行更丰富地测试。

    6 测试工程
    6.1 测试工程概览
    使用Robotium进行自动化测试,测试工程为一个Android Junit Test工程,可以依赖被测工程,与可以选择独立存在。
    关联被测工程源码的好处在于可以调用被测工程的代码,因此可以更容易地获取到被测应用内部的状态,例如拿到被测应用ListView内部填充的数据等等。而这样也会带来一些弊端:
    1.测试工程的自动化编译打包也需要关联被测工程,脚本复杂度及维护成本增加
    2.如果采用R.id.xxx方式获取控件的话,被测工程增加、删除布局文件都可能影响到测试工程的编译结果
    3.如果被测应用进行了代码混淆,引用被测工程的代码复杂度将大大提高
    鉴于此,应用宝采用的是脱离被测工程的方式,同一份测试apk可以同时测试多个版本的被测应用,另外,即使大家选择有源码的方式,也不建议使用R.id.xxx的方式获取控件。
    测试工程需要在AndroidManifest.xml文件中注册instrumentation用于指定被测应用:

        instrumentation 
            android:targetPackage="com.robotium.android.notepad" 
            android:name="android.test.InstrumentationTestRunner"

    在同一个测试工程中我们可以只注册一个instrumentation,也可以同时注册多个,例如当被测应用有多个,而测试工程又不想分别建立多个时,则可以使用注册多个的方法。首先,先编写一个继承自android.test.InstrumentationTestRunner的自定义InstrumentationTestRunner,然后同样地在AndroidManifest.xml中注册:

    instrumentation 
            android:targetPackage="com.robotium.android.anothernotepad" 
            android:name=".instrumentation.InstrumentationTestRunner" 
    

    6.2 测试用例
    6.2.1 测试用例生命周期
    测试用例基于Android Junit,每个用例遵循以下三个步骤:
    1)首先,执行setUp()方法,用于初始化。
    2)然后,执行以public且方法名以test开头的用例方法。
    3)最后,执行tearDown()方法,用于释放资源等
    另外,由于许多用例都需要拥有同样的功能特点,例如需要能够进行出错重试与出错截图等等,因此,可以编写一个共有的测试基类,应用宝测试工程中所有的测试类均继承自SingleLaunchActivityTestCase2这个类。

    6.2.2 测试用例编写
    测试用例编写的质量直接关系到用例的稳定性、维护成本以及是否能发现有效问题等等,因此是自动化测试中的关键一环。
    首先,是确定测试用例的来源。
    当开始准备编写自动化测试用例时,需要确定测试用例的来源,即需要明确例如以下几个方面:
     哪些功能是主要功能、哪些功能可以自动化
     用例的优先级、作用的测试阶段
     测试一个功能需要哪些验证点
    不同的项目组需要思考的点可能不一样,但目的是一致的,需要明确测试用例的来源,而不是任意地开始编写用例。应用宝中采用CheckList的形式,通过与各业务线讨论评审的方式确定关键功能、是否自动化、用例优先级、测试验证点等等。
    然后,应该合理地去设计自动化测试用例
    在设计自动化测试用例时,除了实现用例来源中的功能步骤外,用例的原子性是需要额外注意的,这将影响到多个用例在一起时是否可以高效稳定地运行。用例的原子性,即指用例间应该保持相对独立,不因用例执行的先后顺序而彼此干拢。
    此外,应该以工程的视角去看待测试用例
    测试代码也应该以工程的视角去看待,包括配置管理、结构管理、项目化运作等等。在编写测试用例过程中也应该尽可能地从工程角度在代码易用性、维护性方面去多加考虑。测试代码也应该要有代码规范,包含命名规范、编写规范、注释规范等等,以使测试用例能高效有质量地运转起来。
    最后,应该验证测试用例的有效性
    自动化测试用例本身也是需要经过验证与测试的,一个测试用例本身运行通过了并不一定代表用例就是有效的。例如可能因为检查点判断有问题导致该用例始终通过,而一般当用例开始交付运行后,如果一直是通过的,那么往往就不会有人关注,且测试人员会认为该模块已经有自动化测试去保障从而容易忽略基本的测试,所以常常无效的自动化测试用例比没有自动化测试更可怕,需要警惕出现无效的测试用例。在编写测试用例时需要验证用例的有效性,在测试用例交付使用后,也应该定期地关注测试用例的运行情况及其有效性。

    6.2.3 测试用例执行
    1. 传统命令行执行方式

    (1)Running all tests:

    adb shell am instrument -w com.tencent.assistant.qa/android.test.InstrumentationTestRunner

    (2)Running a single testcase:

    adb shell am instrument -w -e class com.tencent.assistant.qa.testcase.nuclear.MobileAccelerateTest com.tencent.assistant.qa/android.test.InstrumentationTestRunner

    (3)Running a single test:

    adb shell am instrument -w -e class com.tencent.assistant.qa.testcase.nuclear.MobileAccelerateTest#testMgr_MobileAccelerate com.tencent.assistant.qa/android.test.InstrumentationTestRunner

    (4)Running multiple tests:

    adb shell am instrument -w -e class com.tencent.assistant.qa.testcase.pangu.FoundTabActivityTest,com.tencent.assistant.qa.testcase.nuclear.AssistantTabActivityTest com.tencent.assistant.qa/android.test.InstrumentationTestRunner

    2.使用spoon执行

    java -jar spoon-runner-1.1.3-SNAPSHOT-jar-with-dependencies.jar

    –apk example-app.apk

    –test-apk example-tests.apk

    –class-name com.tencent.assistant.qa.testcase.common.SearchTest

    robutim1

    3. 在Eclipse中执行
    选择一个测试类后,右键Run As —— Android Junit Test执行即可
    注:在Run Configuration中,如设置有多个Instrumentation runner,则需要指定InstrumentationRunner,如图13所示:

    图13
    图13 配置Run Configuration

    6.2.4 测试用例管理
    当编写了较多测试用例时,就需要将测试用例分类管理起来,以方便统一维护及用例分级。基于Junit的测试可以使用TestSuite的方式进行管理。
    由于在测试执行时,不同的用例执行时间长短不同,且作用的测试阶段也各不相同阶,因此在进行用例管理时,需要明确用例的级别,例如区分是核心功能用例还是普通用例,从而将不同级别的用例放于一处进行管理,在执行时才可以有针对性地进行测试。

    6.3 测试报告
    6.3.1 Spoon报告
    Spoon是一个由主导有okhttp、retrofit、leakcanary等众多优秀开源项目的Square公司在GitHub上的开源项目,志力于改善基于Instrumentation的测试。通过分布式地在多台手机上同时执行基于Instrumentation的测试用例,并且在测试完成后生成统一的拥有测试结果概览、截图、运行时日志等等功能的HTML形式测试报告,Spoon可以更加快速有效地对Android终端进行自动化测试。
    项目开源地址:https://github.com/square/spoon
    测试采用的Spoon生成,生成报告如图14所示,其中绿条表示用例通过,红条表示用例失败:

    图14
    图14 Spoon报告首页

    点击红条可跳转至失败用例的报告详情页,如图15所示:

    图15
    图15 失败用例的报告详情页

    用例采用出错重试并截图机制,当用例失败时进行截图,并往后开启截取一系列运行时的图片,每个用例右边有四个按钮,分别为将截图以gif格式播放、展示多台手机下同一用例运行情况、运行时日志查看、javadoc文档链接。
    例如点击右3按钮查看运行时日志,如图16所示:

    图16
    图16 运行时日志

    6.3.2 历史数据聚合报告
    Spoon会类似单元测试形式的XML报告文件,因此其他测试平台可以通过解析junit-reports目录下的XML报告获取用例执行的详情数据,对每次的测试进行入库存储,积累日常的测试数据,生成历史记录的测试报告页面。

    图17
    图17 历史数据聚合报告

    7 持续集成
    7.1 Jenkins介绍
    Jenkins,原名Hudson,2011年改为现在的名字,它是一个开源的实现持续集成的软件工具。官方网站:http://jenkins-ci.org/。
    Jenkins 能实施监控集成中存在的错误,提供详细的日志文件和提醒功能,还能用图表的形式形象地展示项目构建的趋势和稳定性。
    7.1.1 参数化构建
    Jenkins支持多种参数化构建,如图18所示:

    图18
    图18 参数化构建

    7.1.2 构建前
    构建前可关联SVN,设置定时触发器等等常规操作。
    此外,安装相应插件后,构建前也可以删除workspace中的指定文件、设置当超时的时候是否停止构建、向workspace事先拷贝文件等等操作

    7.1.3 构建
    构建可以增加如图19所示的诸多构建步骤:

    图19
    图19 构建步骤

    常用的有Execute shell(在Linux机器中执行时),用于执行shell脚本
    Execute Windows batch command(在Windows机器中执行时),用于执行bat批处理脚本

    7.1.4 构建后
    构建后可以选择如图20所示的构建后步骤,常用的有邮件发送、触发新的构建任务、传递参数等等功能。

    图20
    图20 构建后步骤

    7.2 整体流程图
    由7.1节可知,Jenkins支持参数化构建、关联SVN、能设定触发时机、支持执行Shell或bat脚本、支持执行后邮件反馈、支持分布式运行等等一系列持续集成的流程。且Jenkins包含丰富的插件可以用于扩展功能,结合实际项目,因此应用宝使用Jenkins来做自化测试的持续集成,整体流程如图21所示。
    BVT自动化测试根据不同的分支支持定时触发、分支监控及手动上传三种方式触发测试。任务创建后,将根据所选择的测试节点执行测试,测试用例采用基于Robotium框架编写,测试执行采用基于Spoon框架执行,因此支持在单台手机上执行也支持同时在多台手机上同时执行。测试执行完成后数据报告将回传服务端进行数据处理,数据处理完成将在相应平台上展示数据报告并邮件反馈相关负责人。

    图21
    图21 整体流程图

    定时触发:用于主干每日夜里执行全量用例
    分支监控:用于监控DB分支,当DB分支有新的构建时,就拉取相应apk进行BVT测试
    手动上传:支持各FT及发布分支手动上传apk文件,手动触发BVT测试
    任务创建:任务创建时会将测试工程进行编译打包生成测试.apk,并会将测试工程中需要用到地脚本文件、jar包插件等统一拷贝至服务端的一个根据job名称命名的临时目录。
    执行测试:在执行测试前,会将服务端该临时目录下的所有文件push至Slave执行机,然后执行相应的初始化脚本,例如卸载安装应用、清理手机中的残留数据等。
    数据处理:在执行测试完成后,执行相应脚本,从手机中pull出测试产物,例如代码覆盖率用的ec文件、性能监控数据、协议日志数据、内存快照文件等。然后使用相应的jar包插件解析测试报告、上传数据至数据库等操作。
    邮件反馈:调用邮件模版将测试报告发送指定的收件人。
    在这种模式下,BVT测试支持自动执行也支持手动触发执行,在Jenkins中以模版形式既可较灵活地进行配置,且配置维护也较为容易。另外任意能连接成为Jenkins节点的PC都可以迅速成为节点PC机,在节点PC上挂上手机即可成为系统的一部分,可以执行BVT自动化测试任务。

  • 相关阅读:
    创建和发送事件
    (实战)为系统类添加NameValueTable属性,并且添加到相关对话框
    使用GetUniqueIndentifier为某类对象连续编码
    中秋小感
    数据库中取随机数的方法讨论
    CVS添加用户的过程和命令列表
    Mysql中获取刚插入的自增长id的三种方法归纳
    关于Action重复执行两遍的原因
    td内容空的时候,如何显示边框线
    2003下 tomcat 连mysql问题的解决
  • 原文地址:https://www.cnblogs.com/dayiran1222/p/5664140.html
Copyright © 2011-2022 走看看