写在前面
Android 的单元测试如何进行配置,在网络上有大量的文章去介绍,这里不再重复。
但是单元测试并不是光配置起来就完事了的,如何真正地测试一些实际的点,是这篇记录需要重点关注的事情。
如何检查 Activity 有没有通过 startActivity 启动另一个 Activity
// 当前使用 robolectric 版本: 4.2
ShadowActivity shadowActivity = Shadows.shadowOf(activity);
// ..执行 startForActivity..
Intent intent = shadowActivity.peekNextStartedActivityForResult().intent;
assertEquals(intent.getComponent().getClassName(), NextActivity.class.getName());
// 这里还可以对 intent 中的数据进行进一步的测试,此处略过
如何模拟 Activity 的生命周期
// launch 的时候,默认就执行了 create -> start -> resume,最后处在 RESUMED
// 如果你在 onCreate 里面就 finish 了,那 launch 完成,就会是 DESTROYED
try (ActivityScenario<YourActivity> scenario = ActivityScenario.launch(YourActivity.class)) {
scenario.onActivity(activity -> {
// 执行 pause
scenario.moveToState(Lifecycle.State.STARTED);
// 执行 stop
scenario.moveToState(Lifecycle.State.CREATED);
// 执行 destroy
scenario.moveToState(Lifecycle.State.DESTROYED);
});
}
如何在启动 Activity 的时候,通过 Intent 传递参数
Intent launchIntent = new Intent(ApplicationProvider.getApplicationContext(), YourActivity.class);
launchIntent.putExtra("key", "value");
try (ActivityScenario<YourActivity> scenario = ActivityScenario.launch(launchIntent)) {
scenario.onActivity(activity -> {
// blablabla
});
}
如何使用 Mockito 来 mock 静态方法
mockito 在 3.5.0 之后,可以对静态方法进行 mock,只要依赖 mockito-inline 即可
try (MockedStatic<YourClass> mockYourClassStatic = Mockito.mockStatic(YourClass.class)) {
mockYourClassStatic.when(() -> YourClass.staticMethod()).thenReturn("mockResult");
// 这个还可以 verify
mockYourClassStatic.verify(() -> YourClass.staticMethod2());
}
注意,这个作用域仅限当前线程
如何将一个单例替换为 mock 或者 spy
通常,我们会将单例替换为 mock 对象,以便于他在后面的程序中,返回我们想要的值
或者,我们会将它替换为 spy 对象,这样就可以用来进行 verify 或者部分 mock
// 先创建真实的,再 mock getInstance,用 spy 去作为返回值返回
YourClass yourClass = YourClass.getIntance();
YourClass spyYourClass = Mockito.spy(yourClass);
MockedStatic<YourClass> mockStaticYourClass = Mockito.mockStatic(YourClass.class);
mockStaticYourClass.when(() -> YourClass.getIntance()).thenReturn(spyYourClass);
// 返回 mock 的话,只要在 thenReturn 中,返回 mock 对象即可,此处不再赘述
如何让单元测试延时
有一个 case 是,有一个 button 上在点击事件发生的时候,做了防抖动的处理,他使用的方式是,调用 SystemClock.elapsedRealtime()来获取时间,和 last 时间进行对比,超过阈值才可以点。
所以在这个 case 中,界面刚起来的时候,实际上是有非常短的时间,这个按钮是点不了的,只是用户是碰不到这种状况的。
那么我们可以用 Robolectric 对 UnitTest 进行时间的指定,使用下列代码
Robolectric.getForegroundThreadScheduler().advanceTo(1500);
如何让 RxJava 异步转同步
这里用的还是 RxJava 1,emmm
RxJavaPlugins.getInstance().registerSchedulersHook(new RxJavaSchedulersHook() {
@Override
public Scheduler getIOScheduler() {
return Schedulers.trampoline();
}
});
RxAndroidPlugins.getInstance().registerSchedulersHook(new RxAndroidSchedulersHook() {
@Override
public Scheduler getMainThreadScheduler() {
return Schedulers.immediate();
}
});
如何在使用 Mockito mock 方法的时候,获取传入的参数
when(yourMock.func(any(), any())).then(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
int arg1 = invocation.getArgument(0);
String arg2 = invocation.getArgument(1);
return null;
}
});
如何使用 Mockito 去 mock 一个返回 void 的方法
doAnswer(answer).when(mockObject).voidMethod();
(未完待续)