android按钮切换frangment,测试应用的 Fragment

Fragment 在应用中充当可重复使用的容器,使您能够在各种 Activity 和布局配置下呈现相同的界面布局。鉴于这些 Fragment 的通用性,请务必验证它们是否能够提供一致的、具有资源效率的体验:

Fragment 在各种布局配置下的外观应一致,包括支持较大屏幕尺寸或横向设备方向的配置。

请勿为 Fragment 创建视图层次结构,除非该 Fragment 对用户可见。

本文档介绍如何在评估每个 Fragment 行为的测试中加入框架提供的 API。

推动 Fragment 的状态

为了帮助设置执行这些测试的条件,AndroidX 提供了一个 FragmentScenario 库,便于您创建 Fragment 并更改其状态。

注意:要成功运行包含 FragmentScenario 对象的测试,请在测试的插桩线程中运行 API 的每个方法。如需详细了解 Android 测试中使用的不同线程,请参阅了解测试中的线程。

声明依赖项

为了按预期使用 FragmentScenario,请在应用的测试 APK 中定义 fragment-testing 工件,如以下代码段所示:

app/build.gradle

dependencies {

def fragment_version = "1.2.4"

// ...

debugImplementation 'androidx.fragment:fragment-testing:$fragment_version'

}

要查看此库的当前版本,请参阅版本页上有关 Fragment 的信息。

创建 Fragment

FragmentScenario 包括用于启动以下类型的 Fragment 的方法:

这些方法还支持以下类型的 Fragment:

包含界面的图形 Fragment。要启动此类 Fragment,请调用 launchFragmentInContainer()。FragmentScenario 将 Fragment 附加到 Activity 的根视图控制器。此托管 Activity 原本为空。

非图形 Fragment(有时称为“无头 Fragment”),用于存储若干 Activity 中包含的信息或对这些信息进行短期处理。要启动此类 Fragment,请调用 launchFragment()。

FragmentScenario 将此类 Fragment 附加到一个完全为空的 Activity,即没有根视图的 Activity。

启动其中一种类型的 Fragment 后,FragmentScenario 将被测 Fragment 推动到 RESUMED 状态。此状态表示 Fragment 正在运行。如果您测试的是图形 Fragment,则它对用户也是可见的,因此您可以使用 Espresso 界面测试评估其界面元素的相关信息。

以下代码段演示了如何启动每种类型的 Fragment:

图形 Fragment 示例

@RunWith(AndroidJUnit4::class)

class MyTestSuite {

@Test fun testEventFragment() {

// The "fragmentArgs" and "factory" arguments are optional.

val fragmentArgs = Bundle().apply {

putInt("selectedListItem", 0)

}

val factory = MyFragmentFactory()

val scenario = launchFragmentInContainer(

fragmentArgs, factory)

onView(withId(R.id.text)).check(matches(withText("Hello World!")))

}

}

非图形 Fragment 示例

@RunWith(AndroidJUnit4::class)

class MyTestSuite {

@Test fun testEventFragment() {

// The "fragmentArgs" and "factory" arguments are optional.

val fragmentArgs = Bundle().apply {

putInt("numElements", 0)

}

val factory = MyFragmentFactory()

val scenario = launchFragment(fragmentArgs, factory)

}

}

重新创建 Fragment

如果设备资源不足,系统可能会清除包含 Fragment 的 Activity,要求您的应用在用户返回到应用时重新创建该 Fragment。要模拟这种情况,请调用 recreate():

@RunWith(AndroidJUnit4::class)

class MyTestSuite {

@Test fun testEventFragment() {

val scenario = launchFragmentInContainer()

scenario.recreate()

}

}

当 FragmentScenario 类重新创建被测 Fragment 时,Fragment 将返回到重新创建前所处的生命周期状态。

将 Fragment 推动到新状态

在应用的界面测试中,通常只需启动并重新创建被测 Fragment 即可。但是,在更精细的单元测试中,您还可以评估 Fragment 从一个生命周期状态转换到另一个生命周期状态时的行为。

要将 Fragment 推动到其他生命周期状态,请调用 moveToState()。此方法支持以下状态作为参数:CREATED、STARTED、RESUMED 和 DESTROYED。此操作会模拟包含您的 Fragment 的 Activity 由于被其他应用或系统操作打断而更改其状态的情况。

注意:如果您将 Fragment 转换为 DESTROYED 状态,则无法将该 Fragment 推动到其他状态,并且无法将其附加到其他 Activity。

以下代码段演示了 moveToState() 的示例用法:

@RunWith(AndroidJUnit4::class)

class MyTestSuite {

@Test fun testEventFragment() {

val scenario = launchFragmentInContainer()

scenario.moveToState(State.CREATED)

}

}

警告:如果您尝试将被测 Fragment 转换为当前状态,FragmentScenario 会将此请求视为空操作,而非异常。特别是,API 允许您连续多次将 Fragment 转换为 DESTROYED 状态。

在 Fragment 中触发操作

要在被测 Fragment 中触发操作,请使用 Espresso 视图匹配器与视图中的元素互动:

@RunWith(AndroidJUnit4::class)

class MyTestSuite {

@Test fun testEventFragment() {

val scenario = launchFragmentInContainer()

onView(withId(R.id.refresh))

.perform(click())

}

}

如果您需要对 Fragment 本身调用方法,例如响应选项菜单中的选择,您可以通过实现 FragmentAction 安全地执行此操作:

@RunWith(AndroidJUnit4::class)

class MyTestSuite {

@Test fun testEventFragment() {

val scenario = launchFragmentInContainer()

scenario.onFragment(fragment ->

fragment.onOptionsItemSelected(clickedItem) {

// Update fragment's state based on selected item.

}

}

}

}

注意:请勿在测试类中保留对传入 onFragment() 的对象的引用。这些引用会占用系统资源,并且引用本身可能会过时,因为框架可以重新创建传入回调方法的 Fragment。

测试对话框操作

FragmentScenario 还支持测试对话框。

即使对话框是图形 Fragment 的实例,您也可以使用 launchFragment() 方法,以便在对话框本身中填充该对话框的元素,而不是在启动对话框的 Activity 中填充。

以下代码段可测试对话框关闭过程:

@RunWith(AndroidJUnit4::class)

class MyTestSuite {

@Test fun testDismissDialogFragment() {

// Assumes that "MyDialogFragment" extends the DialogFragment class.

with(launchFragment()) {

onFragment { fragment ->

assertThat(fragment.dialog).isNotNull()

assertThat(fragment.requireDialog().isShowing).isTrue()

fragment.dismiss()

fragment.requireFragmentManager().executePendingTransactions()

assertThat(fragment.dialog).isNull()

}

// Assumes that the dialog had a button

// containing the text "Cancel".

onView(withText("Cancel")).check(doesNotExist())

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值