Nano Hash - криптовалюты, майнинг, программирование

Уничтожить и перезапустить Activity с библиотекой поддержки тестирования

Используя старые тесты в стиле JUnit3 в Android, я мог сделать следующее, чтобы удалить и перезапустить активность:

Instrumentation inst = getInstrumentation();
Activity activity = inst.getActivity();
// do something
activity.finish();
Assert.assertTrue(this.activity.isFinishing());
activity = inst.getActivity();
// assert that activity's state is restored

Как я могу сделать то же самое, используя новую библиотеку поддержки тестирования? Меня устраивает использование Espresso и/или UI Automator или любого другого механизма, предоставляемого новой библиотекой.

Обновление:

Я пробовал следующее:

Activity activity = activityTestRule.getActivity();
// do something
activity.finish();
Assert.assertTrue(this.activity.isFinishing());
activity = activityTestRule.getActivity();
// assert that activity's state is restored

Однако похоже, что ActivityTestRule.getActivity() не перезапускает активность.


  • Я бы предположил, что часть finish() не должна отличаться от предыдущей. Я не знаю, будет ли getActivity(), вызванный на вашем ActivityTestRule, воссоздавать разрушенную активность или нет. 12.02.2016
  • @CommonsWare Я попробовал это, и, похоже, это не перезапускает действие. 12.02.2016
  • Теперь, когда я думаю об этом, я не совсем уверен, какое состояние вы ожидаете восстановить после finish(). Вы можете попробовать вызвать launchActivity() после finish() и посмотреть, что произойдет, хотя это создаст новый экземпляр. Или, возможно, вы могли бы добавить его самостоятельно. Разветвить ActivityTestRule и взломать! 12.02.2016
  • @CommonsWare Возможно, это проблема XY. Первоначальная мотивация — протестировать следующую последовательность действий в моем приложении: 1. Запустить действие. 2. Введите некоторые данные. 3. Уничтожить активность, активировав onSaveInstanceState(). 4. Восстановить активность в предыдущем состоянии. 5. Подтвердите, что ранее введенные данные все еще находятся в правильных представлениях. --- Так есть ли лучший способ проверить это? 12.02.2016
  • Возможно, это проблема XY... ну, я мужчина, так что это моя пара хромосом, если вы это имеете в виду. :-) Уничтожить активность, вызывая onSaveInstanceState() -- onSaveInstanceState() не вызывается при уничтожении активности. Это вызвано, потому что действие претерпевает изменение конфигурации. finish() не должно вызывать onSaveInstanceState(). Так есть ли лучший способ проверить это? -- вы можете попробовать UIAutomation.setRotation() и посмотреть, вызовет ли это onSaveInstanceState(). 12.02.2016
  • @CommonsWare Что такое проблема XY? 13.02.2016
  • @CommonsWare Насколько я понимаю, изменение ориентации приведет к уничтожению активности. Это неправильно? 13.02.2016
  • Что такое проблема XY? -- да, но моя интерпретация забавна! изменение ориентации приведет к уничтожению активности - правильно. Однако обратное неверно: уничтожение активности не приводит к изменению конфигурации. onSaveInstanceState() привязан к изменениям конфигурации (плюс некоторые сценарии, связанные с задачами, но только для неуничтоженных активностей). onSaveInstanceState() не привязан к уничтожению по другим причинам. 13.02.2016
  • @ Code-Apprentice, но не могли бы вы сказать, как решить эту проблему в тестах эспрессо? 21.02.2017
  • @Morozov У меня не было времени проверить ни один из ответов с тех пор, как я задал этот вопрос. 21.02.2017

Ответы:


1

Как упоминалось в @CommonsWare, пользовательское правило очень полезно. Вот мое простое решение (возможны многие улучшения, но это всего лишь быстрая структура, на которой можно построить):

public class ControlledActivityTestRule<T extends Activity> extends ActivityTestRule<T> {
    public ControlledActivityTestRule(Class<T> activityClass) {
        super(activityClass, false);
    }

    public ControlledActivityTestRule(Class<T> activityClass, boolean initialTouchMode) {
        super(activityClass, initialTouchMode, true);
    }

    public ControlledActivityTestRule(Class<T> activityClass, boolean initialTouchMode, boolean launchActivity) {
        super(activityClass, initialTouchMode, launchActivity);
    }

    public void finish() {
        finishActivity();
    }

    public void relaunchActivity() {
        finishActivity();
        launchActivity();
    }

    public void launchActivity() {
        launchActivity(getActivityIntent());
    }
}

Обратите внимание: если вы сделаете это таким образом, этот класс должен быть в пакете android.support.test.rule для доступа к приватному методу пакета ActivityTestRule#finishActivity. Затем в вашем тестовом примере реализуйте это правило:

@Rule
public ControlledActivityTestRule<TestFountainPreferenceActivity> actRule = new ControlledActivityTestRule<>(TestFountainPreferenceActivity.class);

Затем в вашем индивидуальном тестовом примере вызовите actRule.finish() и actRule.launchActivity(), чтобы убить и перезапустить его. Или вы можете вызвать actRule.relaunchActivity(), если вам не нужно ничего делать между его уничтожением и повторным запуском. Обратите внимание: вы можете передать третий параметр false, чтобы отложить запуск действия, если у вас есть начальный запуск, а затем вызвать actRule.launchActivity(), чтобы запустить его, но вы потеряете доступ к некоторым встроенным дескрипторам, таким как #afterActivityLaunched и #afterActivityFinished().

21.04.2016
  • Правильно, #finishActivity защищен пакетом, поэтому я открываю его с помощью предоставленного метода #finish. 16.11.2016
  • Есть ли способ расширить его, чтобы воссозданная активность получала Bundle из onSaveInstanceState? 01.03.2017

  • 2

    Как говорят JCricket и djunod, способ сделать это — создать собственное правило. Проблема, с которой я столкнулся с их решениями, заключается в том, что метод finishActivity защищен пакетом, и вы можете использовать его в своем пользовательском правиле тестирования.

    Это мое решение:

    public class RelaunchActivityRule<T extends Activity> extends ActivityTestRule<T> {
    
      public RelaunchActivityRule(Class<T> activityClass) {
        super(activityClass,false);
      }
    
      public RelaunchActivityRule(Class<T> activityClass, boolean initialTouchMode) {
        super(activityClass, initialTouchMode,true);
      }
    
      public RelaunchActivityRule(Class<T> activityClass, boolean initialTouchMode,
          boolean launchActivity) {
        super(activityClass, initialTouchMode, launchActivity);
      }
    
      @Override protected void afterActivityFinished() {
        super.afterActivityFinished();
        launchActivity(getActivityIntent());
      }
    }
    
    25.05.2017

    3

    Ответ JCricket сработал для меня, как только я добавил туда сон...

    package android.support.test.rule;
    
    public class ControlledActivityTestRule<T extends Activity> extends ActivityTestRule<T> {
        public ControlledActivityTestRule(Class<T> activityClass) {
            super(activityClass, false);
        }
    
        public ControlledActivityTestRule(Class<T> activityClass, boolean initialTouchMode) {
            super(activityClass, initialTouchMode, true);
        }
    
        public ControlledActivityTestRule(Class<T> activityClass, boolean initialTouchMode, boolean launchActivity) {
            super(activityClass, initialTouchMode, launchActivity);
        }
    
        public void finish() {
            finishActivity();
        }
    
        public void relaunchActivity(int seconds) {
            finishActivity();
            sleep(seconds);
            launchActivity();
            sleep(seconds);
        }
    
        public void launchActivity() {
            launchActivity(getActivityIntent());
        }
    
        public void sleep(int seconds) {
            if (seconds > 0) {
                try {
                    Thread.sleep(seconds * 1000);
                } catch (Exception ex) {
                }
            }
        }
    }
    

    Затем я смог провести тест с итерациями:

    @Rule
    public ControlledActivityTestRule<MainActivity> mActivityRule = new ControlledActivityTestRule<>(MainActivity.class);
    
    @Test
    public void testOAA310() {
        int count = 1000;
        for (int i = 0; i < count; i++) {
            testCaseOAA310();
            mActivityRule.relaunchActivity(5);
        }
    }
    
    void testCaseOAA310() { /* ... blah blah blah... */ }
    
    14.11.2016
  • Почему testOAA310() звонит сам себе? Это похоже на бесконечную рекурсию. 14.11.2016
  • testOAA310 вызывает testCaseOAA310... не себя. 14.11.2016
  • В чем разница в названиях этих методов? 14.11.2016
  • OIC... тест против testCase... это кажется плохим различием, потому что это не было сразу очевидно для меня 14.11.2016
  • Просто из любопытства, что не так, что вам нужно поспать? Это не ужасно, так как тестируется, но я ненавижу спать, потому что это подрывает доверие к правильному сценарию тестирования. У меня были некоторые первоначальные проблемы с синхронностью, но обычно они объяснялись какой-то другой ошибкой кодирования, которая оставляла активным что-то, что должно было быть уничтожено. 16.11.2016
  • Я считаю, что getInstrumentation().waitForIdleSync(); будет предпочтительной альтернативой сну 28.02.2017

  • 4

    Попробуйте создать собственное правило. Вызовите launchActivity(getActivityIntent()) в методе afterActivityFinished, он перезапустит действие после завершения.

    public class RestartActivityRule<T extends Activity> extends ActivityTestRule<T> {
    
        public RestartActivityRule(Class<T> activityClass) {
            super(activityClass,false);
        }
    
        public RestartActivityRule(Class<T> activityClass, boolean initialTouchMode) {
            super(activityClass, initialTouchMode,true);
        }
    
        public RestartActivityRule(Class<T> activityClass, boolean initialTouchMode,
          boolean launchActivity) {
            super(activityClass, initialTouchMode, launchActivity);
        }
    
        @Override protected void afterActivityFinished() {
            super.afterActivityFinished();
            launchActivity(getActivityIntent());
        }
    }
    
    25.05.2017
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..