Android单元测试:内容更新篇
Posted 唯鹿
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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.class
,constants
配置也被移除,所以默认可以去除@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开始也支持了官方测试库,并推荐使用它们。
变更有以下几个方面:
- 使用
AndroidJUnit4
代替RobolectricTestRunner
:
// 之前
@RunWith(RobolectricTestRunner.class)
public class MainActivityTest
// 现在
@RunWith(AndroidJUnit4.class)
public class MainActivityTest
- 之前使用
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);
- 获取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分支上,便于大家查阅。
内容暂时就这么多。后面如果新的改动,我也会更新在这篇博客当中。
2020.01.16更新:
更新gradle至3.x以后,原本的存放class文件目录发生了改变。所以使用jacoco
时,需要修改指定的类文件夹(检查的覆盖类)地址:
/intermediates/classes/debug
修改为:
/intermediates/javac/debug/compileDebugJavaWithJavac/classes
以上是关于Android单元测试:内容更新篇的主要内容,如果未能解决你的问题,请参考以下文章