Testing multiple activities with espresso

Solution 1:

Yes, it is possible. In one of the samples they have demoed this here https://github.com/googlesamples/android-testing/blob/master/ui/espresso/BasicSample/app/src/androidTest/java/com/example/android/testing/espresso/BasicSample/ChangeTextBehaviorTest.java

@Test
public void changeText_newActivity() {
    // Type text and then press the button.
    onView(withId(R.id.editTextUserInput)).perform(typeText(STRING_TO_BE_TYPED),
            closeSoftKeyboard());
    onView(withId(R.id.activityChangeTextBtn)).perform(click());

    // This view is in a different Activity, no need to tell Espresso.
    onView(withId(R.id.show_text_view)).check(matches(withText(STRING_TO_BE_TYPED)));
}

Read the inline comment.

Waiting for the new activity to load is taken care of implicitly by Espresso.

Solution 2:

It is absolutely possible to write an Espresso (or any instrumentation based) test that crosses multiple Activities. You have to start out with one Activity, but can navigate through the UI of your application to other Activities. The only caveat - due to security restrictions, the test flow must stay within your application's process.

Solution 3:

I've tested this like:

onView(withId(R.id.hello_visitor)).perform(click());
pressBack();
onView(withId(R.id.hello_visitor)).check(matches(isDisplayed())); //fails here

The click action starts a new activity, obviously.

Solution 4:

Let's say you have two activities: HomeActivity and SearchResultsActivity. For the test, you want to do some actions on HomeActivity, and verify the result on SearchResultsActivity. Then the test will be written like below:

public class SearchTest extends ActivityInstrumentationTestCase2<HomeActivity> {

    public SearchTest() {
        super(HomeActivity.class);
    }

    protected void setUp() throws Exception {
        super.setUp();
        getActivity(); // launch HomeActivity
    }

    protected void tearDown() throws Exception {
        super.tearDown();
    }

    public void testSearch() {
        onView(withId(R.id.edit_text_search_input)).perform(typeText("Hello World"));
        onView(withId(R.id.button_search)).perform(click());
        // at this point, another activity SearchResultsActivity is started
        onView(withId(R.id.text_view_search_result)).check(matches(withText(containsString("Hello World"))));
    }

}

So the only thing you need to care, is that you should extends the test class from ActivityInstrumentationTestCase2<FirstActivity>, and call super(FirstActivity.class) in your constructor.

Above example is fairly easy.

Advance example (when startActivityForResult happens):

Sometimes it's really confusing to write a test, where you still have two activities A and B, and the application-flow is different than above:

  1. user does nothing on activity A, but activity A calls startActivityForResult to launch activity B;
  2. then user makes some inputs and clicks on activity B (this part is the real test);
  3. finally activity B exits, it calls setResult and resumes activity A (you need to verify result here).

Even though the whole testing part happens on activity B, you may just need to verify one tiny piece on activity A, but your test should extend from ActivityInstrumentationTestCase2<ActivityWhoCallsStartActivityForResult> which is activity A, but not activity B. Otherwise, when test part is done, activity A won't be resumed, you have no chance to verify your result.