Rooh Al-mahaba
Rooh Al-mahaba

Reputation: 674

android espresso test is fails always in text matching

I have a problem in espresso test, I don't know why matching the text is always fail with me, I even tried to create simple app has two activities, the first activity has textview and two buttons one button show toast another go next activity, during the recording when add assertion to the text and the code generated correctly I run the test it always fails showing this error:

android.support.test.espresso.NoMatchingViewException: No views in hierarchy found matching: (with id: com.example.admin.testtest2demoo:id/textView and with text: is "Rooh" and Child at position 0 in parent Child at position 0 in parent with id: android:id/content and is displayed on the screen to the user)

here the test code :

package com.example.admin.testtest2demoo; 

@LargeTest
@RunWith(AndroidJUnit4.class)
public class MainActivityTest {

@Rule
public ActivityTestRule<MainActivity> mActivityTestRule = new ActivityTestRule<>(MainActivity.class);

@Test
public void mainActivityTest() {

    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    ///when click on this button show toast
    ViewInteraction appCompatButton = onView(
            allOf(withId(R.id.button2), withText("show SomeThing"),
                    childAtPosition(
                            childAtPosition(
                                    withId(android.R.id.content),
                                    0),
                            2),
                    isDisplayed()));
    appCompatButton.perform(click());

    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    ///when click on this button show toast
    ViewInteraction appCompatButton2 = onView(
            allOf(withId(R.id.button2), withText("show SomeThing"),
                    childAtPosition(
                            childAtPosition(
                                    withId(android.R.id.content),
                                    0),
                            2),
                    isDisplayed()));
    appCompatButton2.perform(click());

    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    ///check the text in first activity (is it Rooh)
    ViewInteraction textView = onView(
            allOf(withId(R.id.textView), withText("Rooh"),
                    childAtPosition(
                            childAtPosition(
                                    withId(android.R.id.content),
                                    0),
                            0),
                    isDisplayed()));
    textView.check(matches(withText("Rooh")));

    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    ///when click on this button go to next activity
    ViewInteraction appCompatButton3 = onView(
            allOf(withId(R.id.button), withText("Go Next"),
                    childAtPosition(
                            childAtPosition(
                                    withId(android.R.id.content),
                                    0),
                            0),
                    isDisplayed()));
    appCompatButton3.perform(click());

    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    ///check the text in second activity (is it Hello World!)
    ViewInteraction textView2 = onView(
            allOf(withId(R.id.tv1), withText("Hello World!"),
                    childAtPosition(
                            allOf(withId(R.id.background),
                                    childAtPosition(
                                            withId(R.id.swipe_refresh_layout),
                                            0)),
                            0),
                    isDisplayed()));
    textView2.check(matches(withText("Hello World!")));
}

private static Matcher<View> childAtPosition(
        final Matcher<View> parentMatcher, final int position) {

    return new TypeSafeMatcher<View>() {
        @Override
        public void describeTo(Description description) {
            description.appendText("Child at position " + position + " in parent ");
            parentMatcher.describeTo(description);
        }

        @Override
        public boolean matchesSafely(View view) {
            ViewParent parent = view.getParent();
            return parent instanceof ViewGroup && parentMatcher.matches(parent)
                    && view.equals(((ViewGroup) parent).getChildAt(position));
        }
    };
}
}

And this the layout of first activity :

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">


<Button
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@+id/button2"
    android:onClick="goNext"
    android:text="Go Next"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/button2"
    app:layout_constraintVertical_bias="0.183" />

<TextView
    android:id="@+id/textView"
    android:layout_width="97dp"
    android:layout_height="27dp"
    android:layout_marginTop="80dp"
    android:gravity="center"
    android:text="Rooh"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.501"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

<Button
    android:id="@+id/button2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@+id/textView"
    android:layout_marginTop="64dp"
    android:onClick="showSomeThing"
    android:text="show SomeThing"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.502"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/textView" />
</android.support.constraint.ConstraintLayout>

And the second activity has only one textview, and also its fails if I add assertion on it.

if I comment the text assertions the test will pass, but if text assertion is there it always fails, I also include sleep after each step (I know its nothing to do with it but just in case), I can not understand the code is generated by the recording and the text is displayed correctly but it says No views in hierarchy found matching!!

what I am doing wrong?! thanks in advance

Upvotes: 3

Views: 3186

Answers (2)

Stanislav Negara
Stanislav Negara

Reputation: 662

This problem is due to assertions relying on UI Automator hierarchy to establish an element's child position, while actions are relying on Espresso hierarchy. During replay, both actions and assertions are performed using Espresso hierarchy, and as a result, assertions are more prone to failures due to child position mismatches between UI Automator and Espresso hierarchies.

There are several workarounds for this limitation:

1) In Android Studio, in File | Settings, open Build, Execution, Deployment | Espresso Test Recorder and set "Assertion depth" to 1. This way, the added assertions will not rely on child positions to identify the asserted elements (the generated test code for the assertion will look very similar to what was suggested in the answer above). The downside is that an assertion might become too general and might match more than one element.

2) Rely on actions to assert existence of certain elements on the screen, e.g., rather than asserting that a button with a particular text exists on the screen, click on it.

3) Record only actions and add assertions manually into the generated Espresso test.

4) Manually tweak the recorded assertions to use proper child positions.

Upvotes: 3

denys
denys

Reputation: 6910

The below code looks totally wrong:

ViewInteraction textView = onView(
            allOf(withId(R.id.textView), withText("Rooh"),
                    childAtPosition(
                            childAtPosition(
                                    withId(android.R.id.content),
                                    0),
                            0),
                    isDisplayed()));
    textView.check(matches(withText("Rooh")));
  1. Based on your layout there is only one TextView component which doesn't have any children. So, childAtPosition() can't be applied to it.

  2. textView.check(matches(withText("Rooh"))); is redundant as you already do this when you declare textView.

You can modify your code to the following one which should work:

ViewInteraction textView = onView(allOf(withId(R.id.textView), withText("Rooh")));
textView.check(matches(isDisplayed()));

More about matching the text you can find here.

Upvotes: 2

Related Questions