web-dev-qa-db-ja.com

Espressoで現在のアクティビティを取得するandroid

複数のアクティビティを横断するテストの場合、現在のアクティビティを取得する方法はありますか?

getActivtiy()メソッドは、テストの開始に使用されたアクティビティを1つだけ提供します。

私は以下のようなものを試しました、

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

    }
    return activity;
}

しかし、私はヌルオブジェクトを取得します。

38
fenrigne123

Espressoでは、ActivityLifecycleMonitorRegistryを使用できますが、公式にはサポートされていないため、将来のバージョンでは機能しない可能性があります。

仕組みは次のとおりです。

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

必要なのが現在のActivityに対してチェックすることだけである場合は、使用することでネイティブのEspressoワンライナーを使用して、予想されるインテントが起動されたことを確認できます。

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

エスプレッソはまた、あなたと一致しない場合、その間に発射された意図を示します。

必要な唯一のセットアップは、テストでActivityTestRuleIntentsTestRuleに置き換えて、起動するインテントを追跡できるようにすることです。そして、このライブラリがあなたのbuild.gradle依存関係:

androidTestCompile 'com.Android.support.test.espresso:espresso-intents:2.2.1'
27
riwnodennyk

文書化されていない内部構造を使用しないため、@ Ryanのバージョンが好きですが、これをさらに短く書くことができます。

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];
}

ただし、Firebase Test Labでテストを実行する場合、これは機能しないことに注意してください。それは失敗します

Java.lang.ClassCastException: com.Android.internal.policy.DecorContext cannot be cast to Android.app.Activity
11
Fabian Streitel

AndroidチームはActivityTestRuleActivityScenario に置き換えました。activityTestRule.getActivity()ActivityTestRuleでできましたが、 ActivityScenario 。ここからActivityを取得するためのソリューションの回避策があります ActivityScenario (@Ryanおよび@Fabianソリューションに触発された)

@get:Rule
var activityRule = ActivityScenarioRule(MainActivity::class.Java)
...
private fun getActivity(): Activity? {
  var activity: Activity? = null
  activityRule.scenario.onActivity {
    activity = it
  }
  return activity
}
7
Tanin
public static Activity getActivity() {
    final Activity[] currentActivity = new Activity[1];
    Espresso.onView(AllOf.allOf(ViewMatchers.withId(Android.R.id.content), isDisplayed())).perform(new ViewAction() {
        @Override
        public Matcher<View> 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];
}
4
Ryan

私は他のソリューションを機能させることができなかったので、これをやらなければなりませんでした:

ActivityTestRuleを宣言します:

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

アクティビティを格納するfinalアクティビティ配列を宣言します。

_private final Activity[] currentActivity = new Activity[1];
_

ライフサイクルの更新を取得するために、アプリケーションコンテキストに登録するヘルパーメソッドを追加します。

_private void monitorCurrentActivity() {
    mainActivityTestRule.getActivity().getApplication()
            .registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
                @Override
                public void onActivityCreated(final Activity activity, final Bundle savedInstanceState) { }

                @Override
                public void onActivityStarted(final Activity activity) { }

                @Override
                public void onActivityResumed(final Activity activity) {
                    currentActivity[0] = activity;
                }

                @Override
                public void onActivityPaused(final Activity activity) { }

                @Override
                public void onActivityStopped(final Activity activity) { }

                @Override
                public void onActivitySaveInstanceState(final Activity activity, final Bundle outState) { }

                @Override
                public void onActivityDestroyed(final Activity activity) { }
            });
}
_

現在のアクティビティを取得するヘルパーメソッドを追加します

_private Activity getCurrentActivity() {
    return currentActivity[0];
}
_

したがって、最初のアクティビティを起動したら、monitorCurrentActivity()を呼び出すだけで、現在のアクティビティへの参照が必要な場合はgetCurrentActivity()を呼び出すだけです。

4
Billy Brawner

テストケースにアクティビティが1つしかない場合は、次のことができます。

1.テストRuleを宣言します

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

2. Activityを取得します:

mActivityTestRule.getActivity()

それはパイです!

2
Slava

ClassFastExceptionなしでこのメソッドを使用できるように、@ Fabian Streitelの回答を改善しました

public static Activity getCurrentActivity() {
    final Activity[] activity = new Activity[1];

    onView(isRoot()).check((view, noViewFoundException) -> {

        View checkedView = view;

        while (checkedView instanceof ViewGroup && ((ViewGroup) checkedView).getChildCount() > 0) {

            checkedView = ((ViewGroup) checkedView).getChildAt(0);

            if (checkedView.getContext() instanceof Activity) {
                activity[0] = (Activity) checkedView.getContext();
                return;
            }
        }
    });
    return activity[0];
}
0
Artem M

おそらくアクティビティがActivityLifecycleMonitorRegistryによって報告された状態ではなかったため、@ lactonによって提案されたソリューションは機能しませんでした。

_Stage.PRE_ON_CREATE_を試してみても、まだアクティビティがありませんでした。

:_activitiy-alias_を使用してアクティビティを開始し、実際のクラスを使用する意味がなかったため、ActivityTestRuleまたはIntentTestRuleを使用できませんでしたエイリアスが機能するかどうかを確認するためにテストする場合のテスト。

これに対する私の解決策は、ActivityLifecycleMonitorRegistryを介してライフサイクルの変更をサブスクライブし、アクティビティが起動されるまでテストスレッドをブロックすることでした。

_// 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<Class<? extends MyActivity>> 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は基本的にラッパーオブジェクトです。配列などを使用して、匿名クラス内の値をキャプチャできます。

0
Bakhshi