最近花了一些时间来调研android的测试框架,除了需要适合做UI测试,还需要保证选取的框架有以下几点特性:

  • 工具开源,易于扩展。
  • 脚本编写简洁,维护成本低。
  • 满足客户端的自动化需求。
  • 便与校验结果的正确性。
  • 可用于持续集成。

目前较热门的开源框架有:Android APIs提供的Instrumentation类、MonkeyRunner、Robotium、Athrun、Appium、UIAutomator等

Instrumentation类:http://developer.android.com/reference/android/app/Instrumentation.html

  • Android APIs提供
  • UI层的自动化
  • 跨进程受到android进程安全限制
  • 扩展后的框架:Robotium, Athrun等

Robotium:http://code.google.com/p/robotium/

  • 基于instrumentation实现,提供的接口可以满足大部分自动化需求,使用方法简单
  • 支持手势、webview、截图等操作
  • 支持Remote Control方式
  • 支持ant、maven打包,与jenkins结合较好
  • 资料丰富,社区活跃,更新频繁
  • 签名问题,待测App和测试App必须使用相同签名
  • 通过solo对象提供操作方法,面向对象方面较差
  • 不支持跨应用测试,Android进程安全限制

Athrun(TMTS):http://code.taobao.org/p/athrun/wiki/index/

  • 淘宝的自动化测试框架,比较小众化,相关资料较少
  • 提供通过id查找所有控件方法,控件对象提供操作方法
  • 不支持Remote Control
  • 不支持跨应用测试

Appium:http://appium.io/

  • 使用WebDriver JSON wire protocol支持iOS和Android的UI测试
  • 支持非常多种语言编写测试脚本
  • Android SDK Level在16及以上时,底层使用的UIAutomator,低于16使用Selendroid

Monkeyrunner:<http://developer.android.com/tools/help/MonkeyRunner.html”>

  • Android SDK提供
  • python脚本,使用monkeyrunner test.py来执行
  • 结果的验证是通过截屏比对图片来实现,验证方式不够灵活

UIAutomator:http://developer.android.com/tools/help/uiautomator/index.html

  • Android提供的框架,支持SDK level 16及以上
  • 打包成jar后push到模拟器中运行,调试相对Robotium不便(其实自己稍微封装下也还OK)
  • 支持跨进程测试!!!这一点比起Robotium来说非常赞
  • 手势操作较少(不过4.3已经提供了不少手势操作啦,还木有试用)
  • 基于Junit 3, 相对于Junit4, Testng等测试框架,Junit 3不具备许多功能(不过看到过Google的开发人员说有打算往Junit4上发展)
  • 不支持WebView
  • 没有测试结果报告文件

最后综合考虑了一下,打算选用UIAutomator,毕竟是Google自己做的,又支持跨进程,我们待测的App也没有太多的webview,所以UIAutomator基本能满足我们的要求。

实际使用后,发现UIAutomator没有提供测试结果报告,这一点是硬伤啊…不过还是有解决办法的,把UIAutomator的输出重定向到一个文件中,再使用https://github.com/dpreussler/automator-log-converter转换成xml的测试报告。这样和jenkins集成后,测试结果就可以使用xUnit Plugin展示出来啦~


近期因工作需要,分析了一些Android的测试框架,在这也分享下整理完的资料。

 

Android测试大致分三大块:

  1. 代码层测试
  2. 用户操作模拟,功能测试
  3. 安装部署及稳定性测试

代码层测试

对于一般java代码,采用传统的Junit测试,开发人员通常会编写重要接口和函数的白盒测试代码,不做过多讨论。

但因Android的特殊运行机制(Dalvik虚拟机),其中存在Application、Activity、Service等特殊组件,而这些组件都涉及到生命周期管理的问题。

为了对这些组件进行测试,Google提供了一套针对性的测试框架,AndroidTestFramework

官方教程链接 http://developer.android.com/training/testing.html

官方api http://developer.android.com/reference/android/test/package-summary.html

其中最为常用的就是针对Activity的测试,即ActivityInstrumentationTestCase2<T>类。

继承该类后可通过getActivity()方法获取Activity的一个mock对象,从而实现各种界面元素的测试。代码如下



Androidinstruments 测试 android 测试网站_Text



public class LoginActivityTest extends ActivityInstrumentationTestCase2<LoginActivity> {
        LoginActivityTest mActivity;
        Button btnLogin;

        public LoginActivityTest(){
      super(LoginActivity.class);//必须实现super(testclass)
        }
    
    @Override
    protected void setUp() throws Exception {
        super.setUp();
        mActivity = getActivity();
                btnLogin = mActivity.findViewById(R.id.btnLogin);
    }

        public void testGetActivity(){
           assertNotNull("can't get LoginActivity" , mActivity);
           assertNotNull("can't get loginButton" , btnLogin);
        }
}



Androidinstruments 测试 android 测试网站_Text



 



需要注意的是,测试代码运行的线程并不是UI线程。因此如果需要对UI元素进行setText或是click之类的操作,需要通过getActivity().runOnUiThread(action)方法执行。代码如下



getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                 btnLogin.click();
            }
        });



 



用户操作模拟,功能测试

虽然AndroidTestFramework可以帮助我们完成各种界面的测试。但是,这些代码的编写非常繁琐。而且在大部分情况下,我们需要的是一个连贯性的,在多个Activity之间存在跳转的业务流程测试。这种测试比较接近传统的白盒测试,只针对可见的UI元素进行操作,模拟用户的行为来完成测试。

Google同样为我们提供了一套专门针对UI元素的测试方案,具体可见http://developer.android.com/tools/testing/testing_ui.html

可是Google的这套UI框架仍然不是很友好。为此,我寻找了一些相对成熟的测试框架来帮助我们。经过一系列分析比较和实际代码测试,在这推荐采用Robotium开源框架做为今后一段时间内的主要业务测试框架。

Robotium介绍

Robotium是一款国外的Android自动化测试框架,主要针对Android平台的应用进行黑盒自动化测试,它提供了模拟各种手势操作(点击、长按、滑动等)、查找和断言机制的API,能够对各种控件进行操作。Robotium结合Android官方提供的测试框架达到对应用程序进行自动化的测试。另外,Robotium 4.0版本已经支持对WebView的操作。Robotium 对Activity,Dialog,Toast,Menu 都是支持的。

源码及相关资料地址:https://code.google.com/p/robotium/

Robotium具有清晰的调用方法、良好的兼容性、完善的文档和大量的实际应用案例,并且支持截屏。最为符合我们目前的实际需求。经实际测试,无需特殊配置即可兼容Jenkins系统。
下面以一段HSA项目中的实际测试代码举例。该测试用例完成从登陆、菜单选取、一直到功能界面输入验证的一个流程。



Androidinstruments 测试 android 测试网站_Text



public class LoginActivityTest extends ActivityInstrumentationTestCase2<LoginActivity> {
    Solo solo;
    LoginActivity mActivity;
    
    public LoginActivityTest(){
        super(LoginActivity.class);
    }
    
    @Override
    protected void setUp() throws Exception {
        super.setUp();

        mActivity = getActivity();//初始LoginActivity
        solo = new Solo(getInstrumentation(),mActivity);//初始Robotium的主要入口,solo对象
    }

    
    public void testLogin(){
        //清除用户名EditText内容
        solo.clearEditText(0);

        //输入"userName" 到用户名EditText
        solo.enterText(0, "userName");
        
        //清除密码EditText内容
        solo.clearEditText(1);

        //输入"userPass" 到密码EditText
        solo.enterText(1, "userPass");
        
        //清除站点EditText内容
        solo.clearEditText(2);

        //输入"siteCode" 到站点EditText
        solo.enterText(2, "siteCode");
        
        //点击登陆按钮
        solo.clickOnButton("登录");
        
        //检验当前界面为MainListActivity
        solo.assertCurrentActivity("Expected MainListActivity activity", "MainListActivity");
        
        //点击动态菜单列表中的第一项,进入下一级子菜单界面
        solo.clickInList(0);

        //检验当前界面为SubMenuActivity
        solo.assertCurrentActivity("Expected SubMenuActivity activity", "SubMenuActivity");
        
        //点击子菜单列表中的第一项,进入功能界面
        solo.clickInList(0);

        //检验当前界面为ReceiveActivity
        solo.assertCurrentActivity("Expected ReceiveActivity activity", "ReceiveActivity");
        
        //点击界面中的"使用当前人员"按钮
        solo.clickOnButton("使用当前人员");

        //输入重量
        solo.enterText(1, "123");
        
        //输入单号
        solo.enterText(2, "21123456798");
        
        //模拟软键盘,发送EditText的ACTION_DONE事件
        solo.getCurrentActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                solo.getEditText(2).onEditorAction(EditorInfo.IME_ACTION_DONE);
            }
        });
        
        //寻找是否有内容为"已扫描1件"的textview, 会自动等待10秒
        boolean succ = solo.searchText("已扫描1件"))
        
        //判断成功
        assertTrue(succ);
    }
}



Androidinstruments 测试 android 测试网站_Text



 



可见,Robotium通过一个solo对象来进行各种事件的模拟,代码清晰易懂,并且完全兼容原生AndroidTestFramework

 

安装部署及稳定性测试

安卓系统最为让人诟病的问题就是碎片化,这点在中国比较明显。大致上,2.3.X 和 4.x 的系统各占半壁江山,此外还存在大量的山寨定制系统。

因此在这推荐两款云端测试工具,Testin和百度云测试。

两个框架测试都很简单,在官网注册账号后上传apk即可,网站会用大量的真机进行安装部署和monkey测试。测试完成后会发送一份测试给注册邮箱。

Testin支持Robotium框架的代码测试,同时上传项目apk和测试apk(相同签名)即可。

Testin地址: http://www.testin.cn/

百度云测试: http://mtc.baidu.com/

 

其他测试框架

Monkey测试

Android SDK开发包中自带一个monkeyrunner的工具,可用来进行monkey测试。
文档地址:

Robolectric

一款基于JVM运行的Android测试框架,最大特点就是不需要启动模拟器,因此速度非常快!
目前已支持大部分原生SDK功能的测试,支持Resource,但对于一些特殊硬件上的模拟还存在欠缺。期待进一步的完善
示例代码:



Androidinstruments 测试 android 测试网站_Text



// Test class for MyActivity
@RunWith(RobolectricTestRunner.class)
public class MyActivityTest {

  @Test
  public void clickingButton_shouldChangeResultsViewText() throws Exception {
    Activity activity = Robolectric.buildActivity(MyActivity.class).create().get();

    Button pressMeButton = (Button) activity.findViewById(R.id.press_me_button);
    TextView results = (TextView) activity.findViewById(R.id.results_text_view);

    pressMeButton.performClick();
    String resultsText = results.getText().toString();
    assertThat(resultsText, equalTo("Testing Android Rocks!"));
  }
}



Androidinstruments 测试 android 测试网站_Text



地址: http://robolectric.org/index.html

 

Google Espresso

Google于2013年10月开源的一款测试框架。据称在Google内部已通过多个项目的实际验证,并可能在未来加入到默认AndroidSDK中。
设计上接近Robotium,主要用于业务端的模拟行为测试。相较Robotium,具有更为强大的UI元素匹配寻找功能和更快的运行速度。
不过经过本人的实际使用,发现该框架的代码编写相对复杂,远不如Robotium来的轻巧。此外,该框架无法运行在默认AndroidTestFramework中(可认为是升级版),且因刚开源,缺少文档和应用案例等资料,导致测试代码编写效率相对低下,故暂时不予采用。
地址: https://code.google.com/p/android-test-kit/wiki/Espresso

Mockito

一款用于Mock测试的主流框架
地址: https://code.google.com/p/mockito/



List mockedList = mock(List.class);
  when(mockedList.get(0)).thenReturn("first");
  System.out.println(mockedList.get(0));




总结

如无意外,接下来一段时间内,Android项目会采用以下的方案搭建测试框架:

  • 代码级: AndroidTestFramework + Junit
  • UI业务模拟: Robotium
  • 安装部署: Testin
  • CI: Jenkins

有兴趣的同学也可关注下Robolectric和Espresso两个框架的进展。