系列文章
- 【玩转 Test】开篇-Android test 介绍
- 【玩转 Test】AndroidX Test 介绍,如何测试 ViewModel 与 LiveData
- 【玩转 Test】Test Doubles 的概念及如何测试 Repository
前言
前三篇文章我们介绍了如何写单元测试,从这篇文章开始,我们介绍一下 集成测试
fragment 和 ViewModel 联系很紧密,我们需要确保 ViewModel 在适当时的时机更新 UI,那么该如何测试这部分内容呢?
Fragment 集成测试
为了在下面的架构上进行 集成测试 ,我们需要尽可能的屏蔽无关代码
例如我们可以使用 empty activity,它不包含 fragment 或 activity 的其他代码。对于数据层,可以使用 test doubles 来替代
这样就可以聚焦于 fragment 和 ViewModel 的代码
FragmentScenario
当你需要测试 activity 和 fragment 时,AndroidX test 中的 FragmentScenario
和 ActivityScenario
的 API 可以帮到你
引入
debugImplementation "androidx.fragment:fragment-testing:$fragmentVersion"
implementation "androidx.test:core:$androidXTestCoreVersion"
使用
这些 API 用于为测试提供 fragment 和 activity ,你可以控制它们的启动情况和生命周期状态
以下代码用于启动 fragment 并传入 bundle
val bundle = Bundle().apply { putString("username", "Flywith24") }
val scenario = launchFragmentInContainer<RepoListFragment>(bundle, R.style.AppTheme)
如果想要控制 fragment 的生命周期状态,可以调用
scenario.moveToState(Lifecycle.State.CREATED)
❝由于 FragmentScenario 是 AndroidX test 一部分,因此在 local test 和 instrumented test 中均可使用
❞
Espresso
如果想要测试 Android 中的 UI 组件可以使用 Espresso
库,使用该库你可以使用 view 并检查它们的状态
引入
androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion"
androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion"
使用
一个 Espresso
有四个最基本的部分
onView()
是 Espresso
中一个常用的静态方法,它意味着接下来要对 view 进行操作
ViewMatches
的职责就是寻找 view ,上图中使用的是 withId()
方法,根据 id 匹配相应的 view。还有一些其他的匹配方法,例如 withText
❝注意:保证
❞ViewMatches
只能匹配到一个 view,否则会抛出AmbiquousviewMatcher Exception
ViewAction
是 view 执行的动作,示例中是 click 方法
通过 ViewAssertion
我们可以判断 view 的状态是否符合我们的预期
❝tips:为了提高响应速度,您可以在开发者选项中将动画关闭
❞
Mockito
Mock
我们在 【玩转 Test】Test Doubles 的概念及如何测试 Repository 中介绍了 test doubles 的类型,其中我们主要介绍了 Fake。今天,我们来介绍 test doubles 的另一种类型:Mock
不同于 Fake
,Mock
侧重于跟踪方法的调用,这么说可能比较抽象,让我们举个栗子
如上图,有一个方法被调用并改变了 UI(更新 text )
如果使用 Mock
,则验证更新 text 的方法是否被正确地调用
如果不使用 Mock
,我们通常会验证 TextView 中的 text 是否符合预期
引入 Mockito
为了进行 Mock
测试,我们需要引入 Mockito
库
androidTestImplementation "org.mockito:mockito-core:2.25.0"
androidTestImplementation "com.linkedin.dexmaker:dexmaker-mockito:2.12.1"
有的小伙伴可能会问了,有什么场景需要使用 Mock
吗?
这里有一个例子比较合适,测试使用 navigation 进行 fragment 的跳转
Testing Navigation
我们有一个 HostFragment ,内部有一个 button,点击可以跳转到 RepoListFragment 并将用户名传递过去
接下来我们来测试这部分的跳转
首先提供第一个 fragment
// GIVEN 显示 fragment
val scenario = launchFragmentInContainer<HostFragment>(Bundle(), R.style.AppTheme)
由于我们使用了 navigation ,因此我们还需要 navigationController
val navController = Mockito.mock(NavController::class.java)
scenario.onFragment {
Navigation.setViewNavController(it.view!!, navController)
}
最后我们执行点击按钮动作并验证 navigation 的跳转和参数传递是否符合要求
// WHEN 点击搜索按钮
onView(withId(R.id.button)).perform(click())
// THEN 验证跳转到 repolist 界面
verify(navController).navigate(HostFragmentDirections.actionHostFragmentToRepoListFragment("Flywith24"))
关于我
我是 Fly_with24