You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Espresso测试App跳转GitHub链接至Chrome并完成断言验证

搞定你的Espresso测试断言与Chrome跳转验证

我来帮你解决这两个Espresso测试的核心问题——列表展示断言和Chrome跳转验证,直接上干货!

一、验证搜索后仓库列表正常展示

首先得处理异步加载的问题,因为搜索GitHub仓库是网络请求,Espresso默认不会等待异步操作完成,所以咱们得先确保数据加载完毕再做断言。

1. 处理异步加载(关键!)

如果你的应用用了Retrofit、Coroutines这类异步框架,最好用IdlingResource来让Espresso等待请求完成。比如自定义一个网络请求的IdlingResource,注册到Espresso的IdlingRegistry里,这样测试会自动等数据加载完再继续。

要是不想自定义IdlingResource,也可以用Espresso的waitForView临时调试,不过IdlingResource是更优雅的方案。

2. 断言列表展示的两种方式

方式1:断言列表有至少一个item

可以自定义一个RecyclerView的item数量断言器,或者用Hamcrest匹配器:

// 自定义断言器示例
class RecyclerViewItemCountAssertion(private val matcher: Matcher<Int>) : ViewAssertion {
    override fun check(view: View, noViewFoundException: NoMatchingViewException?) {
        if (noViewFoundException != null) throw noViewFoundException
        val recyclerView = view as RecyclerView
        val adapter = recyclerView.adapter ?: throw AssertionError("RecyclerView adapter is null")
        assertThat(adapter.itemCount, matcher)
    }

    companion object {
        fun greaterThan(count: Int): RecyclerViewItemCountAssertion {
            return RecyclerViewItemCountAssertion(GreaterThan(count))
        }
    }
}

// 测试代码里用这个断言
onView(withId(R.id.repo_recycler_view))
    .check(RecyclerViewItemCountAssertion.greaterThan(0))

方式2:断言某个预期的仓库内容存在

如果知道搜索后一定会出现某个仓库(比如搜索"android"会有google/android),可以直接匹配item的文本:

// 输入搜索词并触发搜索
onView(withId(R.id.search_input))
    .perform(typeText("android"), closeSoftKeyboard())
onView(withId(R.id.search_button))
    .perform(click())

// 断言列表里有目标仓库
onView(withId(R.id.repo_recycler_view))
    .perform(RecyclerViewActions.scrollTo<RepoViewHolder>(hasDescendant(withText("google/android"))))
    .check(matches(hasDescendant(withText("google/android"))))

二、验证点击仓库后Chrome打开对应网页

这个需要用到Espresso-Intents库来捕获和验证应用发出的Intent,因为打开Chrome是通过系统Intent跳转的。

1. 添加依赖

先在build.gradle里加Espresso-Intents的依赖:

androidTestImplementation 'androidx.test.espresso:espresso-intents:3.5.1'

2. 测试代码示例

@Test
fun clickFirstRepo_OpensChromeWithCorrectUrl() {
    // 1. 先完成搜索,确保列表加载完成
    onView(withId(R.id.search_input))
        .perform(typeText("android"), closeSoftKeyboard())
    onView(withId(R.id.search_button))
        .perform(click())
    // 等待列表加载(这里用之前的IdlingResource或者等待逻辑)

    // 2. 初始化Intents,准备捕获Intent
    Intents.init()

    try {
        // 3. 点击列表首个item
        onView(withId(R.id.repo_recycler_view))
            .perform(RecyclerViewActions.actionOnItemAtPosition<RepoViewHolder>(0, click()))

        // 4. 验证Intent是否符合预期:打开Chrome,URL正确
        // 这里可以先获取首个item的实际URL,不用硬编码
        val firstRepoUrl = getFirstRepoUrl() // 你需要自己实现这个方法,比如从ViewModel/Adapter取数据

        intended(allOf(
            hasAction(Intent.ACTION_VIEW),
            hasData(Uri.parse(firstRepoUrl)),
            hasPackage("com.android.chrome") // 指定Chrome的包名
        ))
    } finally {
        // 5. 释放Intents资源
        Intents.release()
    }
}

// 示例:从Adapter获取首个仓库的URL
private fun getFirstRepoUrl(): String {
    val scenario = ActivityScenario.launch(MainActivity::class.java)
    var repoUrl = ""
    scenario.onActivity { activity ->
        val recyclerView = activity.findViewById<RecyclerView>(R.id.repo_recycler_view)
        val adapter = recyclerView.adapter as RepoAdapter
        repoUrl = adapter.repos[0].url
    }
    return repoUrl
}

3. 关键注意点

  • 确保测试设备上安装了Chrome,并且应用有权限打开外部应用(一般默认允许,但如果有运行时权限,测试里要提前授予)。
  • 如果你的应用支持选择浏览器,而你需求是强制跳Chrome,直接指定hasPackage("com.android.chrome")就能精准验证。

最后小提示

  • 测试前最好清空应用缓存,避免之前的搜索结果干扰。
  • 用ActivityScenario来启动Activity,比旧的ActivityTestRule更灵活。

内容的提问来源于stack exchange,提问作者philomath

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:19:14