Robolectric Android单元测试框架
概念
Robolectric
Robolectric is a unit test framework that de-fangs the Android SDK jar so you can test-drive the development of your Android app. Tests run inside the JVM on your workstation in seconds.
TDD
Test-driven development 测试驱动开发
是一种软件开发过程中的应用方法,由极限编程中倡导,以其倡导先写测试程序,然后编码实现其功能得名。测试驱动开发始于20世纪90年代。测试驱动开发的目的是取得快速反馈并使用“illustrate the main line”方法来构建程序。
Javassist
一个开源的分析、编辑和创建Java字节码的类库
优势
Robolectric在其所提供的测试框架中,完全模拟了Android SDK的jar文件(不会再有恼人的stub异常),它使得我们的测试可以运行于JVM之上(速度得到大幅度的提升),因此我们可以用它对Android应用进行测试驱动开发。Roblectric同时实现了Android中对XML的解析,模拟了View,Layout,以及资源的加载,它使得Android的环境对于开发人员来说更像是一个黑盒,从而使开发人员不用大量使用mock,就可以方便的对资源状态和Android相关的代码进行测试。
原理
Robolectric使用了javassist在运行时动态修改Android.jar中类的byte code,Robolectric会在JVM加载Android.jar包的时候,重写其中类的方法。Roblectroic会让这些方法有返回值(null或是0) 而不是抛出异常 ,或者将这些方法调用转向Shadow Objects来模拟Android SDK的实现。Shadow Objects是Robolectric在运行时插入到Android.jar包相应的类中的,它们会实际处理方法的调用,并记录相应的状态,以备在assert的时候进行查询。
集成
Gradle
testCompile "org.robolectric:robolectric:3.1.4"
@RunWith(RobolectricTestRunner.class)@Config(constants = BuildConfig.class)public class SandwichTest { }
Annotate your test with the Robolectric test runner,
Note that you must specify the constants field which points to the BuildConfig.class generated by the build system. Robolectric uses the constants in the class to compute the output paths used by Gradle when building your project. Without these values, Robolectric will not be able to find your merged manifest, resources, or assets
Add the following to your build.gradle:
Maven
<dependency> <groupId>org.robolectric</groupId> <artifactId>robolectric</artifactId> <version>3.1.4</version> <scope>test</scope></dependency>
@RunWith(RobolectricTestRunner.class)public class SandwichTest { }
Annotate your test with the base test runner
Add the following to you pom.xml
Use
配置
指定一些适配的属性,比如语言、屏幕尺寸、白天黑夜等
创建一个名为robolectric.properties
配置SDK Level
@Config(sdk = Build.VERSION_CODES.JELLY_BEAN)
配置Application
@Config(application = CustomApplication.class)
配置 资源文件
@Config(manifest = "some/build/path/AndroidManifest.xml")@Config(resourceDir = "...")@Config(assetDir = "...")
配置属性文件
sdk=18 manifest=path/AndroidManifest.xml shadows=my.package.ShadowFoo
//配置语言,指向文件地址 values-en-port/strings.xml@Config(qualifiers="en-port")
操作Activity生命周期
ActivityController controller = Robolectric.buildActivity(TestActivity.class).create().start(); Activity activity = controller.get();//测试执行resume,其它生命周期一样controller.resume();//检测该周期结束后的数据变化//如果你要测试全部生命周期Activity activity = Robolectric.buildActivity(TestActivity.class).create().start().resume().visible().get();//you can simulate starting the Activity with an intent,you can put data in intentIntent intent = new Intent(Intent.ACTION_VIEW); intent.putExtra("id",1); Activity activity = Robolectric.buildActivity(TestActivity.class).withIntent(intent).create().get();//restore saved instance stateBundle saveInstanceState = new Bundle(); Activity activity = Robolectric.buildActivity(TestActivity.class).create() .restoreInstanceState(saveInstanceState).get();
Fragment,Service,SupportFragment也有相应的 FragmentController, ServiceController, SupportFragmentController来测试他们的生命周期
notes
the test artifacts feature is enabled by default, and the setting to enable/disable test artifacts can be found in File Menu -> Settings -> Build, Execution, Deployment -> Build Tools -> Gradle -> Experimental.
参考资料
http://robolectric.org/custom-test-runner/
http://blog.csdn.net/moubenmao_jun/article/details/17242107