Android Espresso:如何在遵循一个 activity 多个片段架构时测试特定片段

Android Espresso: How do I test a specific Fragment when following one activity to several fragment architecture

我的应用包含一个 Activity 多个 Fragments

我想用 Espresso 测试 Fragments 的 UI。不过我运行陷入了一个问题。

如何测试未添加到 onCreate 中的 ActivityFragment。我在 Fragments 中看到的所有示例都涉及在 onCreate 中添加 Fragment。 那么我怎样才能告诉 Espresso 转到特定的 Fragment 并从那里开始呢?

谢谢

Espresso 只有在显示时才能测试 Fragments。这要求它们由 Activity 显示。

根据您当前的设置,您必须使用 Espresso click() 以您的方式(就像用户那样)达到您实际想要测试的 Fragment

在我的一个项目中,我有一个显示 FragmentsViewPager。对于那些 Fragments 我使用自定义 FragmentTestRule 来单独测试它们。我可以直接启动每个 Fragment 并使用 Espresso 来测试它。参见

您还可以:

  • 不要使用 FragmentsActivities 更容易测试。您可以单独测试每个 Activity。在大多数情况下,FragmentsActivities 相比没有任何优势。 Fragments 只会增加实施和测试的难度。
  • 使您的 FragmentActivity 在创建时直接显示某个 Fragment。例如。通过为您的 FragmentActivity 提供额外的特殊意图。但这会向您的应用添加测试代码,这通常不是一个好的解决方案。

只需使用 Activity 的 SupportFragmentManager 显示片段。

例如 (Kotlin) ActivityTestRule:

@Rule
@JvmField
var activityRule = ActivityTestRule(MainActivity::class.java)

只需在测试前执行此操作:

@Before
fun setup() {
    activityRule.activity.supportFragmentManager.beginTransaction().replace(R.id.main_activity_container_for_your_fragments, FragmentToShow(), "fragment-tag").commitAllowingStateLoss()
    Thread.sleep(500)
}

如果您使用的是导航架构组件,则可以通过在测试开始时深度链接到目标片段(使用适当的参数)来立即测试每个片段。

@Rule
@JvmField
var activityRule = ActivityTestRule(MainActivity::class.java)

protected fun launchFragment(destinationId: Int,
                             argBundle: Bundle? = null) {
    val launchFragmentIntent = buildLaunchFragmentIntent(destinationId, argBundle)
    activityRule.launchActivity(launchFragmentIntent)
}

private fun buildLaunchFragmentIntent(destinationId: Int, argBundle: Bundle?): Intent =
        NavDeepLinkBuilder(InstrumentationRegistry.getInstrumentation().targetContext)
                .setGraph(R.navigation.navigation)
                .setComponentName(MainActivity::class.java)
                .setDestination(destinationId)
                .setArguments(argBundle)
                .createTaskStackBuilder().intents[0]

destinationId 是导航图中的片段目的地 ID。这是您准备好启动片段后将完成的调用示例:

launchFragment(R.id.target_fragment, targetBundle())

private fun targetBundle(): Bundle? {
    val bundle = Bundle()
    bundle.putString(ARGUMENT_ID, "Argument needed by fragment")
    return bundle
}

这里也回答的比较详细:

所以,根据几家公司的模式和推荐做法。您需要为每个视图编写有针对性的封闭测试,无论是 activity、片段、对话框片段还是自定义视图。

首先你需要通过gradle将以下库导入到你的项目中,如果你使用gradle的方式如下

debugImplementation 'androidx.fragment:fragment-testing:1.2.0-rc03'
debugImplementation 'androidx.test:core:1.3.0-alpha03'

对于 Kotlin,debugImplementation 'androidx.test:core-ktx:1.3.0-alpha03'

为了独立于 activity 测试片段,您可以 start/launch 按以下方式进行测试:

@Test
    fun sampleTesting(){
        launchFragmentInContainer<YourFragment>()
        onView(withId(R.id.sample_view_id)).perform(click())
    }

这样,您可以从 activity 中独立测试您的片段,这也是实现封闭和有针对性的 ui 测试的推荐方法之一。有关完整详细信息,您可以从 android 文档

中阅读片段测试文档

https://developer.android.com/training/basics/fragments/testing

而且我发现这个包含大量测试示例的存储库非常有用,尽管它非常限于具有超级简单测试的测试用例的复杂性。虽然它可以是 guide 开始。

https://github.com/android/testing-samples