Get Current Activity in Espresso android

匿名 (未验证) 提交于 2019-12-03 01:16:02

问题:

In case of a test that crosses multiple activities, is there a way to get current activity?

getActivtiy() method just gives one activity that was used to start the test.

I tried something like below,

public Activity getCurrentActivity() {     Activity activity = null;     ActivityManager am = (ActivityManager) this.getActivity().getSystemService(Context.ACTIVITY_SERVICE);     List taskInfo = am.getRunningTasks(1);     try {         Class> myClass = taskInfo.get(0).topActivity.getClass();         activity = (Activity) myClass.newInstance();     }     catch (Exception e) {      }     return activity; }

but I get null object.

回答1:

In Espresso, you can use ActivityLifecycleMonitorRegistry but it is not officially supported, so it may not work in future versions.

Here is how it works:

Activity getCurrentActivity() throws Throwable {   getInstrumentation().waitForIdleSync();   final Activity[] activity = new Activity[1];   runTestOnUiThread(new Runnable() {     @Override     public void run() {       java.util.Collection activities = ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(Stage.RESUMED);       activity[0] = Iterables.getOnlyElement(activities);   }});   return activity[0]; }


回答2:

If all you need is to make the check against current Activity, use may get along with native Espresso one-liner to check that expected intent was launched:

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

Espresso will also show you the intents fired in the meanwhile if not matching yours.

The only setup you need is to replace ActivityTestRule with IntentsTestRule in the test to let it keep track of the intents launching. And make sure this library is in your build.gradle dependencies:

androidTestCompile 'com.android.support.test.espresso:espresso-intents:2.2.1'


回答3:

I like @Ryan's version as it doesn't use undocumented internals, but you can write this even shorter:

private Activity getCurrentActivity() {     final Activity[] activity = new Activity[1];     onView(isRoot()).check(new ViewAssertion() {         @Override         public void check(View view, NoMatchingViewException noViewFoundException) {             activity[0] = (Activity) view.getContext();         }     });     return activity[0]; }

Please be aware, though that this will not work when running your tests in Firebase Test Lab. That fails with

java.lang.ClassCastException: com.android.internal.policy.DecorContext cannot be cast to android.app.Activity


回答4:

If you have the only Activity in your test case, you can do:

1. declare you test Rule

@Rule public ActivityTestRule mActivityTestRule = new ActivityTestRule(TestActivity.class);

2. get you Activity:

mActivityTestRule.getActivity()

That's a piece of pie!



回答5:

public static Activity getActivity() {     final Activity[] currentActivity = new Activity[1];     onView(allOf(withId(android.R.id.content), isDisplayed())).perform(new ViewAction() {         @Override         public Matcher getConstraints() {             return isAssignableFrom(View.class);         }          @Override         public String getDescription() {             return "getting text from a TextView";         }          @Override         public void perform(UiController uiController, View view) {             if (view.getContext() instanceof Activity) {                 Activity activity1 = ((Activity)view.getContext());                 currentActivity[0] = activity1;             }         }     });     return currentActivity[0]; }


回答6:

build.gradle

androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2',                 {             exclude group: 'com.android.support', module: 'support-annotations'         })

And, in your Instrumented test class

 @Rule     public ActivityTestRule intentsTestRule = new ActivityTestRule(MainActivity.class);      MainActivity mainActivity;      @Before     public void setUp() throws Exception {         mainActivity = intentsTestRule.getActivity(); //now Activity's view gets created         //Because Activity's view creation happens in UI Thread, so all the test cases, here, are used by UI Thread     }


回答7:

Solution proposed by @lacton didn't work for me, probably because activity was not in a state that was reported by ActivityLifecycleMonitorRegistry.

I even tried Stage.PRE_ON_CREATE still didn't get any activity.

Note: I could not use the ActivityTestRule or IntentTestRule because I was starting my activity using activitiy-alias and didn't make any sense to use the actual class in the tests when I want to test to see if the alias works.

My solution to this was subscribing to lifecycle changes through ActivityLifecycleMonitorRegistry and blocking the test thread until activity is launched:

// NOTE: make sure this is a strong reference (move up as a class field) otherwise will be GCed and you will not stably receive updates. ActivityLifecycleCallback lifeCycleCallback = new ActivityLifecycleCallback() {             @Override             public void onActivityLifecycleChanged(Activity activity, Stage stage) {                 classHolder.setValue(((MyActivity) activity).getClass());                  // release the test thread                 lock.countDown();             }          };  // used to block the test thread until activity is launched final CountDownLatch lock = new CountDownLatch(1); final Holder> classHolder = new Holder(); instrumentation.runOnMainSync(new Runnable() {    @Override     public void run() {         ActivityLifecycleMonitorRegistry.getInstance().addLifecycleCallback(lifeCycleCallback);      } });  // start the Activity intent.setClassName(context, MyApp.class.getPackage().getName() + ".MyActivityAlias"); context.startActivity(intent); // wait for activity to start lock.await();  // continue with the tests assertTrue(classHolder.hasValue()); assertTrue(classHolder.getValue().isAssignableFrom(MyActivity.class));

Holder is basically a wrapper object. You can use an array or anything else to capture a value inside the anonymous class.



回答8:

The accepted answer may not work in many espresso tests. The following works with espresso version 2.2.2 and Android compile/target SDK 27 running on API 25 devices:

@Nullable private Activity getActivity() {     Activity currentActivity = null;      Collection resumedActivities = ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(RESUMED);     if (resumedActivities.iterator().hasNext()){         currentActivity = (Activity) resumedActivities.iterator().next();     }     return currentActivity; }


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!