17

I am using ActivityScenarioRule for Espresso UI Testing and I wanted to get access to the method getStringArray(), calling which requires the Activity . So, is there any way to retrieve the Activity by the ActivityScenarioRule , maybe something similar to getActivity in ActivityTestRule.

@Rule
    public ActivityScenarioRule activityScenarioRule = new ActivityScenarioRule<>(MainActivity.class);

I am not using ActivityTestRule, because it is deprecated!

Satyam Bansal
  • 363
  • 1
  • 4
  • 11
  • Try this approach, which doesn't need to use `onActivity()`: https://stackoverflow.com/questions/34683956/how-to-get-a-view-from-within-espresso-to-pass-into-an-idlingresource#49496282 – Mr-IDE Nov 19 '21 at 04:58

4 Answers4

28

Since it appears you're using Java, here's how you'd do it:

@Rule
ActivityScenarioRule<MainActivity> activityScenarioRule = new ActivityScenarioRule<>(MainActivity.class);

@Test
public void test() {
    activityScenarioRule.getScenario().onActivity(activity -> {
        // use 'activity'.
    });
}

Please read the documentation for more info on these new ways of interacting with the activity under test.

gosr
  • 4,593
  • 9
  • 46
  • 82
6

For anyone who wants Activity, but that without need to re-write all tests to run on UI-thread, a fairly straightforward Java way to get it:

Waiting for UI

Assume you want to test if a dialog is shown after some delay, the onActivity(...) hook runs on UI-thread, which means waiting in there would cause the dialog to be nerver shown.

  • In such cases you need to keep a strong-reference to ActivityScenario (as that prevents Activity close).
  • Test should wait for onActivity(...) hook to be called, then keep passed Activity's reference.
  • Finally, move test logic out of onActivity(...) hook.

Example

private ActivityScenario mActivityScenario;

@After
public void tearDown() throws Exception {
  if (mActivityScenario != null) {
    mActivityScenario.close();
  }
  mActivityScenario = null;
}

@Override
public Activity getActivity() {
  if (mActivityScenario == null) {
    mActivityScenario = ActivityScenario.launch(getActivityClassForScenario());
  }
  return tryAcquireScenarioActivity(mActivityScenario);
}

protected static Activity tryAcquireScenarioActivity(ActivityScenario activityScenario) {
  Semaphore activityResource = new Semaphore(0);
  Activity[] scenarioActivity = new Activity[1];
  activityScenario.onActivity(activity -> {
    scenarioActivity[0] = activity;
    activityResource.release();
  });
  try {
    activityResource.tryAcquire(15000, TimeUnit.MILLISECONDS);
  } catch (InterruptedException e) {
    Assert.fail("Failed to acquire activity scenario semaphore");
  }
  Assert.assertNotNull("Scenario Activity should be non-null", scenarioActivity[0]);
  return scenarioActivity[0];
}
Top-Master
  • 7,611
  • 5
  • 39
  • 71
Julian C
  • 545
  • 5
  • 6
3

Espresso states the following:

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.

When there is no other way I use the following method to get an arbitrary activity from an ActivityScenarioRule. It uses onActivity mentioned in the accepted answer:

private <T extends Activity> T getActivity(ActivityScenarioRule<T> activityScenarioRule) {
        AtomicReference<T> activityRef = new AtomicReference<>();
        activityScenarioRule.getScenario().onActivity(activityRef::set);
        return activityRef.get();
    }

Any onView(...) code inside onActivity led to a timeout in my testcases. So, I extracted the activity and used it with success outside the onActivity. Beware tho! See the statement above.

tim.k
  • 39
  • 5
  • The activity has to be packaged inside something to avoid the effectively final error in Java. – tim.k Feb 12 '21 at 10:50
  • This Kotlin function worked for me private fun getActivity(): Activity { val activityRef: AtomicReference = AtomicReference() rule.scenario.onActivity { activityRef.set(it) } return activityRef.get() } – Kenneth Murerwa Jan 04 '23 at 10:26
0
@Test
    fun checkForUpdate() {
        val scenario = ActivityScenario.launch(MainActivity::class.java)
        scenario.onActivity {
            UpdateTool.checkForUpdate(it)
        }
    }
shuidi
  • 81
  • 1
  • 2
  • 1
    While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value. – Donald Duck Nov 15 '21 at 19:20