软件测试学习交流群:925205234
简单理解原理:
Android的app需要运行在delvik上面,我们开发的Android app是在JVM上面,开发之前需要下载各个API-Level的SDK,下载的每个SDK都有一个android.jar包,在android_sdk_home/platforms/下面可以看到。开发一个项目的时候,我们需要指定一个API-Level,其实就是将android.jar加入到这个项目的build path里面去。这样项目就可以编译打包了。我们的代码必须运行在真机或模拟器上面。IDE和SDK只提供了开发和编译一个项目的环境,并没有提供运行这个项目的环境,原因是因为android.jar里面的class实现是不完整的,它们只是一些stub,如果打开android.jar下的代码去看,发现所有方法只有一行实现:
Throw RuntimeException(“stub!!”);
运行的单元测试代码要引用android.jar相关代码,就要提供一套完整的运行环境。为了解决这个问题,提出了MVP、MVVM等架构,架构其实是将一层抽离出来。
Robolectric就是这样的:通过实现一套JVM能运行的Android代码,然后在运行单元测试代码时去截取android的相关代码调用,然后转到他们的实现代码去执行这个调用过程。
Robolectric环境搭建(Windows环境下Android Studio):
Gradle中 app下的build.gradle中:
Dependencies{
…
testCompile ‘junit:junit:4.12’
testCompile “org.robolectric:robolectric:3.0”
}
注意:如果写成testCompile,则测试代码放在test文件夹中;如果写成androidTest,则测试代码放在androidTest文件夹中。
其中的Robolectric最新版本号可能会变,可以上jcenter查看一下最新的版本号。
Android Studio中配置:
1.将Build Variant里面的Test Artifact选择为Unit Test,如果找不到Build Variant,可以选择View->Tool Windows->Build Variant。
2.Mac下还需要配置一个东西:菜单栏选择Run->Edit Configuration->Defaults->JUnit,在Configuration tab将working directory改成$MODULE_DIR$。这个配置是Robolectric官方文档提到的。
注意:Robolectric目前不支持android 5.1 API Level22,编译时sdk=21或者一下。
项目工程与test工程:
项目工程是放在app/src/main/java/com/example/administrator/robolectricdemo下,
测试工程是放在app/src/test/java/com/example/administrator/robolectricdemo下。
注意:单元测试test工程在编译打包时并不会编译进apk中。
Github Demo:
地址:
简单实例:
假设app里面有两个activity:MainActivity和LoginActivity,MainActivity如上图所示的工程,为了方便查看最好在测试工程里边定义为MainActivityTest。MainActivity里边有一个Button,点击这个Button跳转到LoginActivity,MainActivity里边代码大概是:
对应的测试类,MainActivityTest代码:
写完之后,开始运行:
1. 直接右键运行。
2. 启动命令行,cd到项目根目录下,运行./gradlew test(windows运行 gradlew test),等待几秒钟,可以看到运行结果。
注意:第一次运行可能需要下载一些library,或者gradle本身,可能需要花一些时间,这个跟unit test本身无关。
Mocking框架并不是必须的:
结合mock框架例如mockito或者模拟出Android SDK,允许测试风格更接近于黑盒测试,使测试更有效的重构和允许测试关注应用程序的行为,而不是Android的实现。
Wiki地址:http://robolectric.org/index.html
Configuring Robolectric
定制Robolectric如何在运行时的行为。
@Config注释。
注释可以应用到类和方法,在类或方法前加该注释。
Configure SDK Level
Robolectric将对你在清单文件中指定的targetSdkVersion进行测试,如果你想测试特定的代码在不同的sdk中的表现水平,可以改变sdk版本通过设置:
@Config(sdk=Build.VERSION_CODES.JELLY_BEAN)
Public class SandwichTest{
@Config(sdk=Build.VERSION_CODES.KITKAT)
Public void getSandwich_shouldReturnHamSandwich(){
}
}
Configure Application Class
Robolectric将尝试创建应用程序类的一个实例,在清单中指定。如果你想提供一个定制的实现中,您可以指定它通过设置:
@Config(application = CustomApplication.class)
public class SandwichTest {
@Config(application = CustomApplicationOverride.class)
public void getSandwich_shouldReturnHamSandwich() {
}
}
Configure Resource Paths
自定义清单文件、资源文件、assests文件夹等,如果你想自定义构建系统:
@Config(manifest = "some/build/path/AndroidManifest.xml")
public class SandwichTest {
@Config(manifest = "other/build/path/AndroidManifest.xml")
public void getSandwich_shouldReturnHamSandwich() {
}
}
默认情况下,Robolectric将假定你的资源和assets位于目录命名res和assests。这些路径被认为相对于清单所在的目录。您可以更改这些值通过添加@Config resourceDir和@Config assetDiroptions 。
更多Config设置信息:http://robolectric.org/configuring/
Activity生命周期回调:
Robolectric 2.2之前都是通过ShadowActivity来调取生命周期中的函数:
ShaowActivity.callOnCreate()。
2.2之后通过ActivityController来改变这一切。它的目标是模仿Android如何创造你的Activities和驱动他们的生命周期。
通常并不直接创建ActivityController,使用Robolectric.buildActivity()开始:
Activity activity =Robolectric.buildActivity(MyAwesomeActivity.class).create().get();
这将创建一个MyAwesomeActivity的新的实例,并调用生命周期的onCreate()。
更多ActivityController的API操作:http://robolectric.org/javadoc/latest/org/robolectric/util/ActivityController.html
Extending Robolectric (扩展)
Shadow Classes(影子类)
Robolectric定义了许多的Shadow类别,修改或扩展Android系统的行为类。当一个Android类被实例化,Robolectric寻找相应的影子类,如果找到一个它创建一个阴影对象关联。
每次方法调用一个Android类,Robolectric确保影子类的调用对应的方法(如果有的话),所以有机会发挥它的魔力。试用于所有的方法,即使是静态和final的方法,因为robolectric非常的棘手。
更多扩展:http://robolectric.org/extending/
自定义运行测试:
一个很好的例子是初始化一个依赖注入框架为您的测试与一组不同的依赖关系。Robolectric有一种方式可以hook测试的生命周期。
地址:http://robolectric.org/custom-test-runner/