本主题介绍了如何在评估每个 Fragment 行为的测试中包含框架提供的 API。
Fragment 在您的应用中充当可重用容器,可让您在各种 Activity 和布局配置中呈现相同的用户界面布局。鉴于 Fragment 的多功能性,验证它们提供一致且资源高效的体验非常重要。请注意以下事项:
- 您的 Fragment 不应依赖于特定的父级 Activity 或 Fragment。
- 除非 Fragment 对用户可见,否则不应创建 Fragment 的视图层次结构。
为了帮助设置执行这些测试的条件,AndroidX fragment-testing
库提供了 FragmentScenario
类来创建 Fragment 并更改其 Lifecycle.State
。
声明依赖项
要使用 FragmentScenario
,请在应用的 build.gradle
文件中,使用 debugImplementation
定义 fragment-testing-manifest
工件,并使用 androidTestImplementation
定义 fragment-testing
工件,如以下示例所示:
Groovy
dependencies { def fragment_version = "1.8.8" debugImplementation "androidx.fragment:fragment-testing-manifest:$fragment_version" androidTestImplementation "androidx.fragment:fragment-testing:$fragment_version" }
Kotlin
dependencies { val fragment_version = "1.8.8" debugImplementation("androidx.fragment:fragment-testing-manifest:$fragment_version") androidTestImplementation("androidx.fragment:fragment-testing:$fragment_version") }
本页面上的测试示例使用 Espresso 和 Truth 库中的断言。如需了解其他可用的测试和断言库,请参阅为 AndroidX Test 设置项目。
创建 Fragment
FragmentScenario
包含以下在测试中启动 Fragment 的方法:
launchInContainer()
,用于测试 Fragment 的用户界面。FragmentScenario
将 Fragment 附加到 Activity 的根视图控制器。此包含 Activity 否则为空。launch()
,用于在没有 Fragment 用户界面的情况下进行测试。FragmentScenario
将此类 Fragment 附加到空 Activity,即没有根视图的 Activity。
启动其中一种 Fragment 类型后,FragmentScenario
会将受测 Fragment 驱动到指定状态。默认情况下,此状态为 RESUMED
,但您可以使用 initialState
参数覆盖此设置。RESUMED
状态表示 Fragment 正在运行并对用户可见。您可以使用 Espresso UI 测试评估其界面元素的信息。
以下代码示例展示了如何使用每种方法启动您的 Fragment:
launchInContainer() 示例
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@Test fun testEventFragment() {
// The "fragmentArgs" argument is optional.
val fragmentArgs = bundleOf(“selectedListItem” to 0)
val scenario = launchFragmentInContainer<EventFragment>(fragmentArgs)
...
}
}
launch() 示例
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@Test fun testEventFragment() {
// The "fragmentArgs" arguments are optional.
val fragmentArgs = bundleOf("numElements" to 0)
val scenario = launchFragment<EventFragment>(fragmentArgs)
...
}
}
提供依赖项
如果您的 Fragment 具有依赖项,您可以通过向 launchInContainer()
或 launch()
方法提供自定义 FragmentFactory
来提供这些依赖项的测试版本。
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@Test fun testEventFragment() {
val someDependency = TestDependency()
launchFragmentInContainer {
EventFragment(someDependency)
}
...
}
}
如需详细了解如何使用 FragmentFactory
为 Fragment 提供依赖项,请参阅Fragment 管理器。
将 Fragment 驱动到新状态
在您的应用界面测试中,通常只需启动受测 Fragment 并从 RESUMED
状态开始测试即可。但在更细粒度的单元测试中,您可能还需要评估 Fragment 从一个生命周期状态转换到另一个生命周期状态时的行为。您可以通过将 initialState
参数传递给任何 launchFragment*()
函数来指定初始状态。
要将 Fragment 驱动到不同的生命周期状态,请调用 moveToState()
。此方法支持以下状态作为参数:CREATED
、STARTED
、RESUMED
和 DESTROYED
。此方法模拟 Fragment 或包含 Fragment 的 Activity 因任何原因更改其状态的情况。
以下示例在 INITIALIZED
状态下启动测试 Fragment,然后将其移动到 RESUMED
状态:
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@Test fun testEventFragment() {
val scenario = launchFragmentInContainer<EventFragment>(
initialState = Lifecycle.State.INITIALIZED
)
// EventFragment has gone through onAttach(), but not onCreate().
// Verify the initial state.
scenario.moveToState(Lifecycle.State.RESUMED)
// EventFragment moves to CREATED -> STARTED -> RESUMED.
...
}
}
重新创建 Fragment
如果您的应用在资源不足的设备上运行,系统可能会销毁包含您的 Fragment 的 Activity。此情况要求您的应用在用户返回时重新创建 Fragment。要模拟此情况,请调用 recreate()
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@Test fun testEventFragment() {
val scenario = launchFragmentInContainer<EventFragment>()
scenario.recreate()
...
}
}
FragmentScenario.recreate()
会销毁 Fragment 及其宿主,然后重新创建它们。当 FragmentScenario
类重新创建受测 Fragment 时,该 Fragment 会返回到销毁之前的生命周期状态。
与界面 Fragment 交互
要在受测 Fragment 中触发界面操作,请使用 Espresso 视图匹配器与视图中的元素交互。
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@Test fun testEventFragment() {
val scenario = launchFragmentInContainer<EventFragment>()
onView(withId(R.id.refresh)).perform(click())
// Assert some expected behavior
...
}
}
如果您需要在 Fragment 本身上调用方法(例如响应选项菜单中的选择),您可以通过使用 FragmentScenario.onFragment()
获取 Fragment 的引用并传入 FragmentAction
来安全地执行此操作。
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@Test fun testEventFragment() {
val scenario = launchFragmentInContainer<EventFragment>()
scenario.onFragment { fragment ->
fragment.myInstanceMethod()
}
}
}
测试对话框操作
FragmentScenario
还支持测试对话框 Fragment。虽然对话框 Fragment 具有界面元素,但其布局是在单独的窗口中填充的,而不是在 Activity 本身中填充。因此,请使用 FragmentScenario.launch()
来测试对话框 Fragment。
以下示例测试对话框关闭过程:
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@Test fun testDismissDialogFragment() {
// Assumes that "MyDialogFragment" extends the DialogFragment class.
with(launchFragment<MyDialogFragment>()) {
onFragment { fragment ->
assertThat(fragment.dialog).isNotNull()
assertThat(fragment.requireDialog().isShowing).isTrue()
fragment.dismiss()
fragment.parentFragmentManager.executePendingTransactions()
assertThat(fragment.dialog).isNull()
}
}
// Assumes that the dialog had a button
// containing the text "Cancel".
onView(withText("Cancel")).check(doesNotExist())
}
}