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

Espresso测试遇NoMatchingViewException:Fragment已显示但测试失败

问题

正在对Fragment的显示状态进行Instrumentation测试,代码中使用了Hilt和Navigation Graph。执行测试时,物理设备上能看到FragmentLogin视图,但测试抛出androidx.test.espresso.NoMatchingViewException,提示找不到id为fragmentLogin的视图,随后应用关闭。

相关代码如下:

FragmentLogin.xml

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <variable
            name="login"
            type="com.nano.modularapp.login.FragmentLogin" />
    </data>
    
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".login.FragmentLogin">

        <TextView
            android:id="@+id/tvSignUpTitle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Welcome in ModularApp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            android:layout_marginTop="20dp"
            android:layout_marginStart="20dp"
            android:textColor="@color/black"
            android:fontFamily="@font/mukta_bold"
            android:textSize="26sp"
            android:textStyle="bold"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintTop_toBottomOf="@id/tvSignUpTitle"
            app:layout_constraintStart_toStartOf="parent"
            android:text="Login"
            android:textColor="@color/black"
            android:layout_marginTop="20dp"
            android:layout_marginStart="20dp"
            android:fontFamily="@font/mukta_medium"
            android:textSize="22sp" />

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            android:layout_margin="20dp">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Email"
                android:textSize="20sp"
                android:layout_marginTop="15dp"
                android:textColor="@color/text_color"
                android:fontFamily="@font/mukta_medium"/>

            <com.google.android.material.textfield.TextInputEditText
                android:id="@+id/editTextEmail"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Email"
                android:layout_marginTop="5dp"
                android:textColor="@color/text_color"
                android:fontFamily="@font/mukta_regular"
                android:textSize="18sp"/>

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Password"
                android:textSize="20sp"
                android:layout_marginTop="20dp"
                android:textColor="@color/text_color"
                android:fontFamily="@font/mukta_medium"
                android:inputType="textEmailAddress"/>

            <com.google.android.material.textfield.TextInputEditText
                android:id="@+id/editTextPassword"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Password"
                android:layout_marginTop="5dp"
                android:textColor="@color/text_color"
                android:fontFamily="@font/mukta_regular"
                android:textSize="18sp"
                android:inputType="textPassword"/>

            <TextView
                android:id="@+id/tvError"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="15sp"
                android:layout_marginTop="15dp"
                android:fontFamily="@font/mukta_regular"
                android:text="@{login.errorMsg}"
                android:textColor="@color/error"/>

            <Button
                android:id="@+id/btnLogin"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Login"
                android:textSize="20sp"
                android:paddingStart="20dp"
                android:paddingEnd="20dp"
                android:layout_marginTop="25dp"
                android:layout_gravity="center"
                android:fontFamily="@font/mukta_semi_bold"/>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal"
                android:padding="8dp"
                android:gravity="center">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textSize="15sp"
                    android:text="Don't have an account?"
                    android:textColor="@color/black"
                    android:fontFamily="@font/mukta_regular"/>

                <TextView
                    android:id="@+id/navigateToSignUp"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textSize="18sp"
                    android:text="  Sign Up"
                    android:textColor="@color/info_blue"
                    android:fontFamily="@font/mukta_medium"/>

            </LinearLayout>

        </LinearLayout>

    </androidx.constraintlayout.widget.ConstraintLayout>

</layout>

FragmentLoginInstrumentedTest.kt

@HiltAndroidTest
@RunWith(AndroidJUnit4::class)
class FragmentLoginInstrumentedTest {

    @get:Rule
    val hiltRule:HiltAndroidRule = HiltAndroidRule(this)

    @get:Rule
    val activityRule: ActivityScenarioRule<HiltTestActivity> = ActivityScenarioRule(HiltTestActivity::class.java)

    @Before
    fun init(){
        hiltRule.inject()
    }

    @Test
    fun test_blankField_expectedEmptyField(){
        //Checking LoginFragment is attached and displayed in screen or not
        launchFragmentInHiltContainer<FragmentLogin>()
        onView(withId(R.id.fragmentLogin)).check(ViewAssertions.matches(isDisplayed()))
    }
}
解决方案
  • 核心原因:FragmentLogin.xml的根布局ConstraintLayout未设置android:id="@+id/fragmentLogin",Espresso无法找到该ID对应的视图,即便Fragment已正常显示。
  • 解决办法1:给根布局添加目标ID
    修改FragmentLogin.xml的根ConstraintLayout,补充ID属性:
    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/fragmentLogin"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".login.FragmentLogin">
    
  • 解决办法2:验证Fragment内已存在的视图
    无需新增ID,直接验证Fragment中已有的可见组件(比如登录按钮btnLogin),这种方式更符合测试逻辑——关键视图显示即可证明Fragment已正确加载:
    @Test
    fun test_blankField_expectedEmptyField(){
        launchFragmentInHiltContainer<FragmentLogin>()
        onView(withId(R.id.btnLogin)).check(ViewAssertions.matches(isDisplayed()))
    }
    
  • 额外提示:若修改后仍有问题,可能需要等待视图完全加载。正式测试可使用Espresso的IdlingResource处理异步场景,临时调试可添加短时间延迟(不推荐用于正式测试用例)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 13:50:56