Android单元测试(十):内容更新篇

距离我上一次写单元测试的内容已经是一年半以前了,在这期间有个别的内容随着相关库的升级也已经过时了。避免“误人子弟”,我对之前的 Demo 进行一下升级,本文就是相关内容的记录。

如果你对单元测试相关内容不了解,请先阅读之前的 九篇博客 。本篇仅是对之前内容的更新。

1.Robolectric配置

首先升级 Robolectric 的依赖至最新:

testImplementation "org.robolectric:robolectric:4.3.1"
复制代码

在根目录的 gradle.properties 文件中添加:

android.enableUnitTestBinaryResources=true
复制代码

之前的配置中,需要通过 @Config 注解指定 constants = BuildConfig.class ,也可指定sdk的版本信息:

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 23)
public class MainActivityTest {

}
复制代码

在4.0开始的版本中,默认不需要指定 constants = BuildConfig.classconstants 配置也被移除,所以默认可以去除 @Config 的这行固定配置。

如果要指定sdk版本的话,可以在 src/test/resources 目录下创建一个名为 robolectric.properties 的文件在你所要生效的包名下。其中更深的包中的值覆盖更浅的包中的值。当测试类或方法有 @Config 注释,这些注释覆盖属性文件中的任何配置。具体如下图所示:

这样相比之前的方式确实友好很多。详细配置及其他用法可以 参看官方文档

2.Robolecture与AndroidX

随着AndroidX的到来,Android官方也提供了相应的测试框架。

testImplementation 'androidx.test:core:1.2.0'
    testImplementation 'androidx.fragment:fragment-testing:1.1.0'
    // AndroidJUnitRunner and JUnit Rules
    testImplementation 'androidx.test:runner:1.2.0'
    testImplementation 'androidx.test:rules:1.2.0'
    // Assertions
    testImplementation 'androidx.test.ext:junit:1.1.1'
    testImplementation 'androidx.test.ext:truth:1.2.0'
    testImplementation 'com.google.truth:truth:1.0'
复制代码

Robolectric 在4.0开始也支持了官方测试库,并推荐使用它们。

变更有以下几个方面:

  1. 使用 AndroidJUnit4 代替 RobolectricTestRunner :
// 之前
@RunWith(RobolectricTestRunner.class)
public class MainActivityTest {

}

// 现在
@RunWith(AndroidJUnit4.class)
public class MainActivityTest {

}
复制代码
  1. 之前使用 RuntimeEnvironment.application 可以获取到Application,现在推荐使用 getApplicationContext 方法获取。
import androidx.test.core.app.ApplicationProvider.getApplicationContext

@Test
public void testResources() {
    Application application = getApplicationContext();
    String appName = application.getString(R.string.app_name);
    assertEquals("AndroidUT", appName);
}
复制代码
  1. 获取Activity方式调整。之前的方式是直接通过 setupActivity 或者 buildActivity 方法获取:
MainActivity activity = Robolectric.setupActivity(MainActivity.class);
// 或者
ActivityController<MainActivity> controller = Robolectric.buildActivity(MainActivity.class);
MainActivity activity = controller.get();
复制代码

现在:

@RunWith(AndroidJUnit4.class)
public class MainActivityTest {

    @Rule
    public ActivityTestRule<MainActivity> activityRule = new ActivityTestRule<>(MainActivity.class);

    private MainActivity mainActivity;

    @Before
    public void setUp(){

        mainActivity = activityRule.getActivity();
        // 或者
        ActivityScenario<MainActivity> scenario = ActivityScenario.launch(MainActivity.class);
        scenario.moveToState(Lifecycle.State.CREATED);
        scenario.onActivity(activity -> {
            mainActivity = activity;
        });
    }

}
复制代码

Fragment 获取方式大同小异,不过要注意添加 testImplementation 'androidx.fragment:fragment-testing:1.1.0' 依赖。

@Test
public void testFragment() {
    FragmentScenario<SampleFragment> scenario = FragmentScenario.launch(SampleFragment.class);
    scenario.onFragment(fragment -> assertNotNull(fragment.getView()));
}
复制代码

对于官方测试库的详细使用可以查看Android的 官方文档

3.AssertJ-Android

之前有提到 AssertJ-Android 这个库,它是AssertJ的拓展,便于我们断言Android View。

由于AndroidX的到来,这个库也就不太适用于未来。官方也觉得他并不是一个好的方式,所以暂停了维护。推荐我们使用Google的 truth 。并且 truth 这个库也内置在官方的测试框架里面。它和 AssertJ 很相似,有兴趣的可以了解一下。

这里我暂时没有使用 truth ,只是用 AssertJ 的方式替换了 AssertJ-Android 。仅仅是个人习惯问题。

之前的方式:

import static org.assertj.android.api.Assertions.assertThat;

 @Test
public void testView() {
    // Button是否可见
    assertThat(mJumpBtn).isVisible();
    // LinearLayout 方向,子View数量
    assertThat(mRoot)
         .isVertical()
         .hasChildCount(4);
    // CheckBox是否未选中
    assertThat(checkBox).isNotChecked();
}
复制代码

修改后:

import static org.assertj.core.api.Assertions.assertThat;

@Test
public void testView() {
	// AssertJ-Android (已不在维护),这里就是用普通方法实现
	// Button是否可见
	assertThat(mJumpBtn.getVisibility()).isEqualTo(View.VISIBLE);
    // LinearLayout 方向,子View数量
    assertThat(mRoot.getOrientation()).isEqualTo(LinearLayout.VERTICAL);
    assertThat(mRoot.getChildCount()).isEqualTo(4);
    // CheckBox是否未选中
    assertThat(checkBox.isChecked()).isEqualTo(false);
}
复制代码

4.当前依赖版本

以下是当前项目所用到的测试框架的依赖版本:

//junit
    testImplementation 'junit:junit:4.12'
	//mockito
    testImplementation "org.mockito:mockito-core:3.1.0"
    //powermock
    testImplementation "org.powermock:powermock-module-junit4:2.0.2"
    testImplementation "org.powermock:powermock-module-junit4-rule:2.0.2"
    testImplementation "org.powermock:powermock-api-mockito2:2.0.2"
    testImplementation "org.powermock:powermock-classloading-xstream:2.0.2"
    //robolectric
    testImplementation "org.robolectric:robolectric:4.3.1"
    //AssertJ
    testImplementation 'org.assertj:assertj-core:3.13.2'

	// AndroidX所需
    testImplementation 'androidx.test:core:1.2.0'
    testImplementation 'androidx.fragment:fragment-testing:1.1.0'
    // AndroidJUnitRunner and JUnit Rules
    testImplementation 'androidx.test:runner:1.2.0'
    testImplementation 'androidx.test:rules:1.2.0'
    // Assertions
    testImplementation 'androidx.test.ext:junit:1.1.1'
    testImplementation 'androidx.test.ext:truth:1.2.0'
    testImplementation 'com.google.truth:truth:1.0'
复制代码

最后我将修改后的代码也已经同步到了 Github 上,master分支是使用 support 28.0 依赖库的,androidx部分的改动放在了androidx分支上,便于大家查阅。

内容暂时就这么多。后面如果新的改动,我也会更新在这篇博客当中。

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章