Получить текущую активность в эспрессо-андроиде
В случае теста, который пересекает несколько действий, существует ли способ получить текущую активность?
Метод getActivtiy() просто дает одно действие, которое было использовано для запуска теста.
Я попробовал что-то вроде ниже,
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;
}
но я получаю нулевой объект.
Ответы
Ответ 1
В 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];
}
Ответ 2
Если вам нужно всего лишь сделать проверку против текущего Activity
, использование может сочетаться с одним эскизом эспрессо, чтобы проверить, что ожидаемое намерение было запущено:
intended(hasComponent(new ComponentName(getTargetContext(), ExpectedActivity.class)));
Espresso также покажет вам намерения, выпущенные между тем, если они не соответствуют вашим.
Единственная настройка, в которой вы нуждаетесь, - это заменить ActivityTestRule
на IntentsTestRule
в тесте, чтобы он отслеживал запуск намерений. И убедитесь, что эта библиотека находится в ваших зависимостях build.gradle
:
androidTestCompile 'com.android.support.test.espresso:espresso-intents:2.2.1'
Ответ 3
Мне нравится версия @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
Ответ 4
Если у вас есть единственное действие в вашем тестовом примере, вы можете сделать:
1. объявите тест Rule
@Rule
public ActivityTestRule<TestActivity> mActivityTestRule = new ActivityTestRule<>(TestActivity.class);
2. получите Activity
:
mActivityTestRule.getActivity()
Это кусок пирога!
Ответ 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<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];
}
Ответ 6
build.gradle
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2',
{
exclude group: 'com.android.support', module: 'support-annotations'
})
И в вашем тестовом классе Instrumented
@Rule
public ActivityTestRule<MainActivity> intentsTestRule = new ActivityTestRule<>(MainActivity.class);
MainActivity mainActivity;
@Before
public void setUp() throws Exception {
mainActivity = intentsTestRule.getActivity(); //now Activity view gets created
//Because Activity view creation happens in UI Thread, so all the test cases, here, are used by UI Thread
}
Ответ 7
Принятый ответ может не работать во многих тестах эспрессо. Следующее работает с эспрессо версии 2.2.2 и Android-компилятором/целевым SDK 27, работающим на устройствах API 25:
@Nullable
private Activity getActivity() {
Activity currentActivity = null;
ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(RESUMED);
Collection resumedActivities = ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(RESUMED);
if (resumedActivities.iterator().hasNext()){
currentActivity = (Activity) resumedActivities.iterator().next();
}
return currentActivity;
}
Ответ 8
Решение, предложенное @lacton, не работало для меня, возможно, потому, что активность не была в состоянии, о котором сообщалось ActivityLifecycleMonitorRegistry
.
Я даже попробовал Stage.PRE_ON_CREATE
, пока не получил никакой активности.
Примечание. Я не мог использовать ActivityTestRule
или IntentTestRule
, потому что начал свою деятельность с помощью activitiy-alias
и не имел смысла использовать фактический класс в тестах, когда Я хочу проверить, работает ли псевдоним.
Мое решение было подписано на изменения жизненного цикла через 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
- это в основном объект-обертка. Вы можете использовать массив или что-нибудь еще, чтобы захватить значение внутри анонимного класса.