Is there any way to know if an activity has been started with Espresso?

10.7k views Asked by At

I'm doing an Activity transition testing with Espresso but I don't know if this is the best way to do it:

public void testStartLogin() {
    onView(withId(R.id.register)).perform(click());
    onView(withId(R.id.login_password)).check(matches(isDisplayed()));
    onView(withId(R.id.login_show_password)).check(matches(isDisplayed()));
}

The last two are from the second activity but this looks horrible for me. Is there any different way?

4

There are 4 answers

1
appoll On BEST ANSWER

Asserting something against a view that belongs to a certain activity is in my opinion a very elegant way of checking if that specific activity has been started. From the official docs:

At the same time, the framework prevents direct access to activities and views of the application because holding on to these objects and operating on them off the UI thread is a major source of test flakiness. Thus, you will not see methods like getView and getCurrentActivity in the Espresso API.

However, there is a way to accomplish what you need, like shown here. In my version, I also defined an assertion method like:

 public void assertCurrentActivityIsInstanceOf(Class<? extends Activity> activityClass) {
    Activity currentActivity = getActivityInstance();
    checkNotNull(currentActivity);
    checkNotNull(activityClass);
    assertTrue(currentActivity.getClass().isAssignableFrom(activityClass));
}

which I used in the test methods.

For my own tests I didn't have any issues using it (Espresso 2.0 !), but it made it somewhat redundant since I would still check the views belonging to that activity. So it works, but I wouldn't recommend it.

Good luck!

EDIT:

There is also the possibility of checking if the intent was sent from your first activity to the second one (check this short tutorial), but that doesn't necessarily mean that the second activity displayed all of its views correctly. You should still check them being displayed, which brings you back to where you started.

0
Be_Negative On

Espresso authors discourage from accessing the actual activity to determine the state of the app.

Just like the real users have no idea what activity is in front of them, they determine where they are in the app by looking at the elements on the screen. I don't think that your current approach looks as horrible.

However, espresso comes with ActivityLifecycleMonitor that tracks states of the activities. You can access it and perform you assertion just like this:

final Activity[] activity = new Activity[1];

InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
        @Override
        public void run() {
           activity[0] =Iterables.getOnlyElement(ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(Stage.RESUMED));
}

assertTrue(activity instanceof MyActivity.class);

Which doesn't look any better than your approach and it also might be flaky and subject to race conditions if your previous activity is doing any work after clicking the registration button.

0
lujop On

You can do with:

intended(hasComponent(new ComponentName(getTargetContext(), ExpectedActivity.class)));

Loot at response from @riwnodennyk

0
baskara On

This short snippet should work:

intended(hasComponent(ExpectedActivity.class.getName()));