複数のアクティビティを横断するテストの場合、現在のアクティビティを取得する方法はありますか?
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;
}
しかし、私はヌルオブジェクトを取得します。
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];
}
必要なのが現在のActivity
に対してチェックすることだけである場合は、使用することでネイティブのEspressoワンライナーを使用して、予想されるインテントが起動されたことを確認できます。
intended(hasComponent(new ComponentName(getTargetContext(), ExpectedActivity.class)));
エスプレッソはまた、あなたと一致しない場合、その間に発射された意図を示します。
必要な唯一のセットアップは、テストでActivityTestRule
をIntentsTestRule
に置き換えて、起動するインテントを追跡できるようにすることです。そして、このライブラリがあなたのbuild.gradle
依存関係:
androidTestCompile 'com.Android.support.test.espresso:espresso-intents:2.2.1'
文書化されていない内部構造を使用しないため、@ 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
AndroidチームはActivityTestRule
を ActivityScenario に置き換えました。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
}
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];
}
私は他のソリューションを機能させることができなかったので、これをやらなければなりませんでした:
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()
を呼び出すだけです。
テストケースにアクティビティが1つしかない場合は、次のことができます。
Rule
を宣言します@Rule
public ActivityTestRule<TestActivity> mActivityTestRule = new ActivityTestRule<>(TestActivity.class);
Activity
を取得します:mActivityTestRule.getActivity()
それはパイです!
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];
}
おそらくアクティビティが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
は基本的にラッパーオブジェクトです。配列などを使用して、匿名クラス内の値をキャプチャできます。