基于Robolectric的Android单元测试 —环境搭建与部署运行

达芬奇密码2018-08-13 16:34

移动端的测试中,因为回归一些逻辑分支比较多的功能时工作量比较大,且不太适合用UI完成,尝试通过单元测试来完成。几经波折终于完成了一个功能的UT用例并在CI上部署运行,现总结如下:

一、Robolectric简介
Robolectric是一款运行在JVM之上的Android单元测试框架。传统的Android Instrumentation单元测试框架必须运行在虚拟机上,测试速度较慢,效率低。而Robolectric模拟了Android sdk的jar包,其会在JVM加载Android.jar包的时候,重写其中类的方法,让这些方法有返回值,不会抛出stub异常 ,或者利用Shadow Objects来模拟方法的实现。因此,Robolectric完全脱离了Android模拟器,用例的运行速度大幅提高。
官网链接:http://robolectric.org/

二、本地环境搭建
  1. 在eclipse中导入或者新建被测android工程
  2. 在android工程的根目录下新建一个test文件夹,在test文件夹中新建src文件夹,用于存放测试代码
  3. 创建一个新的java工程
  4. 把java工程下默认的src移除bulid path(点击鼠标右键可见),把src删除
  5. 把android工程下的test/src文件夹,加到java工程来(点击鼠标右键,选择build path、link souce),就可以在java工程中看到测试代码了,但实质上代码是放在android工程的目录下的
  6. Java工程,右键build path 、configure build path中,Projects里把android工程加进来,注意调整顺序使blog_android位于robolectric的下面
  7. configure build path中,Add Library,把juint4加进来
  8. java工程,把下面依赖的android包和robolectric包导入,可把依赖包存放在android工程的test/libs下。必须的包:android.jar、maps.jar、robolectric-2.4-jar-with-dependencies.jar

三、编写并运行用例
  Robolectric是基于juint4的,所以样式类似于普通juint的单元测试,以下是一个简单的例子
@RunWith(RobolectricTestRunner.class)
@Config(emulateSdk=18)
public class ButtonTest {
ButtonActivity buttonActivity;
Button button1;
TextView textview;
@Before
public void setUp() throws Exception {
buttonActivity = Robolectric.buildActivity(ButtonActivity.class).create().get();
textview = (TextView) buttonActivity.findViewById(R.id.TextView1);
button1 = (Button) buttonActivity.findViewById(R.id.Button1);
}
@Test
public void buttontest() throws Exception {
button1.performClick();
assertEquals("你点击了开始按钮!", textview.getText().toString());
}
}

运行用例,run configuration设置,test下最下方Select选择Eclipse JUnit Launcher;Arguments里Working directory选择android工程。


当用于项目的时候还有一些需要注意的地方:
  1. 网上有的例子启动activity,使用buttonActivity  = new ButtonActivity(),我试了下在robolectric-2.4-jar-with-dependencies包下是不行的;
  2. 如果配置的android sdk版本比较高,比如@Config(emulateSdk=21),运行用例会提示Robolectric还不支持;
  3. Robolectric默认采用项目根目录下的AndroidManifest.xml和res资源文件,当采用上述方法运行用例时,则会采用android工程下的AndroidManifest.xml和res。如果不想用默认的,也可以指定文件:      @Config(manifest = "",resourcesDir="")
  4. 运行用例的时候,Roblectric会先去创建Android工程的Application的实例。在实际的项目中,发现有一些清理的方法和xml的写法robolectric不识别,一种做法是在BeforeClass中把Application的class文件和需要修改的xml文件替换掉,在AfterClass中换回来。Robolectric也提供一种替换方式@Config(application = CustomApplication.class)

四、CI部署与持续集成
  采用ant编译运行测试代码,编写build构建文件。需要先编译开发代码,再编译测试代码,才能运行用例,target可以按照如下形式组织:
<!-- 初始化工作,创建文件夹等 -->
<target name="init"></target>
<!-- 根据工程中的资源文件生成R.java文件 -->
<target name="gen-R" depends="init"></target>
<!-- 编译aidl文件 -->
<target name="aidl" depends="gen-R"></target>
<!-- 编译开发代码源文件 -->
<target name="compile_android" depends="aidl"></target>
<!-- 编译测试代码源文件 -->
<target name="compile" depends="compile_android"></target>
<!-- junit运行测试用例 -->
<target name="test-run" depends="compile"></target>
<!-- junitreport生成html报告 -->
<target name="test-report-junit" depends="test-run"></target>


有几点需要注意的地方:
  1. 如果build文件没有放到android工程的根目录下且代码中没有指定res和AndroidManifest.xml,在运行测试用例前需要把android工程的res和AndroidManifest.xml拷贝到build文件的同级目录下;
  2. classpath中junit.jar要位于android.jar之前;
  3. 编译和运行测试用例的classpath中需要包含编译开发代码的目标路径和开发代码的所有依赖jar包。 

Jenkins上部署运行:虽然在本地创建了一个java工程,但其实代码源码是存放在android工程中的,因此只需要从git上更新android工程,然后ant运行build构建文件,最后再配置发送邮件。注意:生成R文件,如果运行用例的服务器是linux的,需要在工程根目录下手动创建gen文件,而windows下会自动创建。


网易云新用户大礼包:https://www.163yun.com/gift

本文来自网易实践者社区,经作者陈天昊授权发布。