How I can get view by id in my espresso tests?

Viewed 4419

I don't understand how I can get a view from the screen in my espresso tests with findViewById.

I'm going to one of a screen in my app with espresso autotest, and then I want to check the screen is correct. For that, I need to get toolbar from the screen and check some of his properties. First I tried to make this with ViewInteractions objects, but I can cast it into View and can't get access to object properties.

I want to use findViewById for getting a view directly, but I can understand how to use it right.

public void goToMyOrders (){
        BottomTabBar bottomTabBar = new BottomTabBar();
        bottomTabBar.profileButton.perform(click());
        myOrderButton.perform(click());
        ViewInteraction toolbarView = onView(allOf(withId(R.id.custom_font_toolbar)));
        toolbarView.getContext();
        toolbarView.check(matches(withText("Мои заказы")));
    }
2 Answers

Nah, I think you got an idea about testing a little wrong. Firstly, Toolbar doesn't extend/inherit TextView, so it can't have text, but you can place a TextView inside Toolbar. I've prepared simple code to show you an idea of automated tests using Espresso.

Create a new sample app, place this layout into your activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

<Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintHeight_percent="0.3"
        app:layout_constraintTop_toTopOf="parent"
        android:background="@color/colorAccent"/>

<TextView
        android:id="@+id/textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="@id/toolbar"
        app:layout_constraintBottom_toBottomOf="@id/toolbar"
        app:layout_constraintLeft_toLeftOf="@id/toolbar"
        app:layout_constraintRight_toRightOf="@id/toolbar"
        android:text="SomeTextBeforeChange"
        android:textColor="#FFFFFF"/>

<Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@id/toolbar"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:text="Change text after click"/>

in your MainActivity:

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Button button = findViewById(R.id.button);
    final TextView textView = findViewById(R.id.textview);
    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            textView.setText("Changed text");
        }
    });
}

}

As you see this might be a similar View like yours - Toolbar, TextView and Button which changes TextView's text.

Let's make an automated test now using Espresso.

  1. In your androidTest subfolder create a new Class, name it e.g MainActivityTest.

  2. Define an ActivityTestRule. Read about it in Android docs You may also need those Gradle dependencies:

    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test:rules:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

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

    Then define a public method with return type void, annotated with @Test. Inside this method you can define your TextView by calling Espresso.onView(ViewMatchers.withId(your.textview.id));

To check whether it contains specified text you need to call `textview.check(ViewAssertions.matches(ViewMatchers.withText("expected text")));

I won't explain those methods what exactly do because their names speak for themselves, but if you had some troubles in understanding them you have plenty resources here on StackOverflow. To my code above, I wrote the following simple test, so you can analyse this if you want:

public class MainActivityTest {

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

@Test
public void checkIfButtonChangesText(){
    // TextView
    ViewInteraction textView = Espresso.onView(ViewMatchers.withId(R.id.textview));
    // Button
    ViewInteraction button = Espresso.onView(ViewMatchers.withId(R.id.button));

    //check if TextView contains text: "SomeTextBeforeChange"
    textView.check(ViewAssertions.matches(ViewMatchers.withText("SomeTextBeforeChange")));

    // analogically with Button, text: "Change text after click"
    button.check(ViewAssertions.matches(ViewMatchers.withText("Change text after click")));

    // perform button click:
    button.perform(ViewActions.click());

    //Check if text has been changed to "Changed text"
    textView.check(ViewAssertions.matches(ViewMatchers.withText("Changed text")));

}

}

you can use ViewAction to get view by findviewbyId in addition to ViewInteraction.

For YourCase it will be like:

Public View getView(int Rid) {
   onView(allOf(withId(Rid))).perform(new ViewAction() {
        @Override
        public Matcher<View> getConstraints() {
            return isAssignableFrom(TextView.class);
        }

        @Override
        public String getDescription() {
            return "getting text from a TextView"; 
        }

        @Override
        public void perform(UiController uiController, View view) {
            TextView tv = (TextView) view; 
        }
    });
    return tv
}

Note: I used textview as a constraint if for textview.You can use other constraints also from ViewMatchers

Related