Robolectric介绍

简介

在Android模拟器或设备运行测试很慢!构建,部署和启动应用程序往往需要一分钟或更长时间。
在Android直接从您的IDE内部运行测试岂不是很好?但容易碰到java.lang.RuntimeException: Stub!
Robolectric不依赖Android SDK jar的安卓单元测试框架,测试在JVM上运行,可以在几秒内完成。
示例:

@RunWith(RobolectricTestRunner.class)
public class MyActivityTest {

  @Test
  public void clickingButton_shouldChangeResultsViewText() throws Exception {
    MyActivity activity = Robolectric.setupActivity(MyActivity.class);

    Button button = (Button) activity.findViewById(R.id.button);
    TextView results = (TextView) activity.findViewById(R.id.results);

    button.performClick();
    assertThat(results.getText().toString()).isEqualTo("Robolectric Rocks!");
  }
}


Robolectric改写Android SDK中的类,使他们可能在普通的JVM上运行。
Robolectric视图和资源及本地C代码实现等东东加载,很容易地提供我们自己的特定的SDK方法实现,比如模拟错误情况或现实世界的sensor行为。

运行测试模拟器之外
Robolectric,您可以在工作站上运行测试,或在常规JVM持续集成环境,没有一个模拟器。正因为如此,德兴,包装和安装 - 上的仿真器的步骤是没有必要的,减少分钟的测试周期秒钟,这样可以快速迭代,并有信心重构代码。
Robolectric的风格更接近黑盒测试,通常不需要Mockito等模拟框架,当然依旧可以与Mockito配合使用。


快速入门

Robolectric与Gradle或Maven配合比较好。新项目推荐使用Gradle。

build.gradle

testCompile“org.robolectric:robolectric:3.0”


测试使用注解即可:

@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class)
public class SandwichTest {
}


注意必须指定constants指向由生成系统生成的BuildConfig.class。Robolectric使用类的常量来计算输出路径(Gradle使用), 否则Robolectric将无法找到manifest,resources或asset。

使用Maven构建

pom.xml:

<dependency>
   <groupId>org.robolectric</groupId>
   <artifactId>robolectric</artifactId>
   <version>3.0</version>
   <scope>test</scope>
</dependency>

测试使用注解即可:

@RunWith(RobolectricTestRunner.class)
public class SandwichTest {
}


如果你引用项目以外的资源(即在AAR依赖)项目以外的资源,需要提供Robolectric一个指针指向AAR在构建系统。

Android Studio

Robolectric适用于Android Studio 1.1.0及以后版本。在"Build Variants" 中开启 unit test支持即可。Linux和Mac中需要编辑“run configurations”,设置工作目录为$MODULE_DIR$。

Robolectric介绍_第1张图片

Robolectric介绍_第2张图片

Eclipse已经不推荐使用,但是可以安装m2e-android(不支持AAR)插件,导入Maven 工程, 点击 "Plugin execution not covered by lifecycle configuration"。
示例工程参见:https://github.com/robolectric/robolectric-samples。

第一个测试

activity的layout如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/login"
        android:text="Login"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>



我们要编写测试断言当用户点击按钮时应用程序启动LoginActivity。

public class WelcomeActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.welcome_activity);

        final View button = findViewById(R.id.login);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startActivity(new Intent(WelcomeActivity.this, LoginActivity.class));
            }
        });
    }
}



检查启动了对应的intent即可:

@RunWith(RobolectricTestRunner.class)
public class WelcomeActivityTest {

    @Test
    public void clickingLogin_shouldStartLoginActivity() {
        WelcomeActivity activity = Robolectric.setupActivity(WelcomeActivity.class);
        activity.findViewById(R.id.login).performClick();

        Intent expectedIntent = new Intent(activity, WelcomeActivity.class);
        assertThat(shadowOf(activity).getNextStartedActivity()).isEqualTo(expectedIntent);
    }
}

注意:目前Robolectric只有API 16/19/21的实例。貌似还不支持API 23等。上述代码不能实际执行,实际执行的参见demo。

后期有空会把上面代码串成实例。


配置Robolectric

  • 配置注解

定制Robolectric的主要方式是通过@Config注解。注释可以应用到的类和方法,同事也可以在基类中定制。

  • 配置SDK级别

Robolectric基于manifest的targetSdkVersion运行代码,可更改设置SDK版本:

@Config(sdk = Build.VERSION_CODES.JELLY_BEAN)
public class SandwichTest {

    @Config(sdk = Build.VERSION_CODES.KITKAT)
    public void getSandwich_shouldReturnHamSandwich() {
    }
}
  • 配置应用程序类

@Config(application = CustomApplication.class)
public class SandwichTest {

    @Config(application = CustomApplicationOverride.class)
    public void getSandwich_shouldReturnHamSandwich() {
    }
}
  • 配置资源路径

Gradle和Maven有默认值,也可自定义:

@Config(manifest = "some/build/path/AndroidManifest.xml")
public class SandwichTest {

    @Config(manifest = "other/build/path/AndroidManifest.xml")
    public void getSandwich_shouldReturnHamSandwich() {
    }
}

默认资源目录res和assets。通过添加resourceDir和assetDir选项到@Config可改变这些值。

  • 配置属性

@Config注解的内容可以在文件中定义robolectric.properties:

sdk=18
manifest=some/build/path/AndroidManifest.xml
shadows=my.package.ShadowFoo,my.package.ShadowBar
  • 系统属性

robolectric.offline - Set to true to disable runtime fetching of jars.
robolectric.dependency.dir - When in offline mode, specifies a folder containing runtime dependencies.
robolectric.dependency.repo.id - Set the ID of the Maven repository to use for the runtime dependencies (default sonatype).
robolectric.dependency.repo.url - Set the URL of the Maven repository to use for the runtime dependencies (default https://oss.sonatype.org/content/groups/public/).
robolectric.logging.enabled - Set to true to enable debug loggin

Gradle可在all部分为单元测试配置系统属性。例如,覆盖Maven仓库URL和ID:

android {
  testOptions {
    unitTests.all {
      systemProperty 'robolectric.dependency.repo.url', 'https://local-mirror/repo'
      systemProperty 'robolectric.dependency.repo.id', 'local'
    }
  }
}



参考资料:
http://tools.android.com/tech-docs/unit-testing-support。


Activity的生命周期

Robolectric2.2之前,大多数的测试直接调用构造函数 (new MyActivity()),然后手动调用的生命周期方法,如OnCreate()。ShadowActivity的方法(例如ShadowActivity.callOnCreate())也经常使用,他们是的ActivityController的前身。ActivityController在Robolectric2.0中引入的。

现在不会直接创建ActivityController,而是使用Robolectric.buildActivity()开始。通常可以这样:

Activity activity = Robolectric.buildActivity(MyAwesomeActivity.class).create().get();

上面创建MyAwesomeActivity实例并调用onCreate()。

要检查onResume()也简单:

ActivityController controller = Robolectric.buildActivity(MyAwesomeActivity.class).create().start();
Activity activity = controller.get();
// assert that something hasn't happened
activityController.resume();
// assert it happened!

类似的方法也包括start(), pause(), stop(), and destroy(),比如测试整个创建生命周期:

Activity activity = Robolectric.buildActivity(MyAwesomeActivity.class).create().start().resume().visible().get();

可以带intent启动Activity:

Intent intent = new Intent(Intent.ACTION_VIEW);
Activity activity = Robolectric.buildActivity(MyAwesomeActivity.class).withIntent(intent).create().get();

或恢复已保存实例的状态:

Bundle savedInstanceState = new Bundle();
Activity activity = Robolectric.buildActivity(MyAwesomeActivity.class)
    .create()
    .restoreInstanceState(savedInstanceState)
    .get();

    
更多资料参见http://robolectric.org/javadoc/latest/org/robolectric/util/ActivityController.html。


附加模块


为了减少对应用外部依赖,Robolectric的shadow被分成各种附加包。主Robolectric模块只提供基础的Android SDK提供的shadow。

SDK Package Robolectric Add-On Package
com.android.support.support-v4 org.robolectric:shadows-support-v4
com.android.support.multidex org.robolectric:shadows-multidex
com.google.android.gms:play-services org.robolectric:shadows-play-services
com.google.android.maps:maps org.robolectric:shadows-maps
org.apache.httpcomponents:httpclient org.robolectric:shadows-httpclient


你可能感兴趣的:(Robolectric介绍)