ProgressBars и Espresso - программирование
Подтвердить что ты не робот

ProgressBars и Espresso

Когда у меня есть ProgressBar в макетах, которые отображаются при запуске некоторых эспрессо-тестов, тогда я сталкиваюсь с:

Caused by: android.support.test.espresso.AppNotIdleException: Looped for 1670 iterations over 60 SECONDS. The following Idle Conditions failed .

Какой хороший способ обойти это? Нашли некоторые хакерские вещи, но искали хороший способ

4b9b3361

Ответ 1

У меня та же проблема. Я не мог понять абсолютно изящное решение, но я также опубликую свой подход.

Что я пытался сделать, это переопределить indeterminateDrawable на ProgressBar. При наличии простой анимации без анимации и теста Espresso не возникает проблема с простоя.

К сожалению, main и androidTest обрабатываются одинаково. Я не нашел способ переопределить стили моего ProgressBar.

Теперь это привело к объединению некоторых идей из https://gist.github.com/Mauin/62c24c8a53593c0a605e#file-progressbar-java и Как определить, Android-приложение запускает UI-тест с помощью Espresso.

Сначала я создал пользовательские классы ProgressBar, один для отладки и один для выпуска. Версия выпуска только вызывает суперконструкторы и ничего не делает. Отладочная версия переопределяет метод setIndeterminateDrawable. С этим я мог бы установить простой вариант, а не анимационный.

Код выпуска:

public class ProgressBar extends android.widget.ProgressBar {

  public ProgressBar(Context context) {
    super(context);
  }

  public ProgressBar(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  public ProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
  }

  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  public ProgressBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
  }

}

Отладочный код:

public class ProgressBar extends android.widget.ProgressBar {

  public ProgressBar(Context context) {
    super(context);
  }

  public ProgressBar(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  public ProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
  }

  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  public ProgressBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
  }

  @SuppressWarnings("deprecation")
  @Override
  public void setIndeterminateDrawable(Drawable d) {
    if (isRunningTest()) {
        d = getResources().getDrawable(R.drawable.ic_replay);
    }
    super.setIndeterminateDrawable(d);
  }

  private boolean isRunningTest() {
    try {
        Class.forName("base.EspressoTestBase");
        return true;
    } catch (ClassNotFoundException e) {
        /* no-op */
    }
    return false;
  }

}

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

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

Ответ 2

Если ProgressBar невидимо при запуске теста, Drawable можно заменить обычным ViewAction:

// Replace the drawable with a static color
onView(isAssignableFrom(ProgressBar.class)).perform(replaceProgressBarDrawable());

// Click a button (that will make the ProgressBar visible)
onView(withText("Show ProgressBar").perform(click());

Пользовательский ViewAction:

public static ViewAction replaceProgressBarDrawable() {
    return actionWithAssertions(new ViewAction() {
        @Override
        public Matcher<View> getConstraints() {
            return isAssignableFrom(ProgressBar.class);
        }

        @Override
        public String getDescription() {
            return "replace the ProgressBar drawable";
        }

        @Override
        public void perform(final UiController uiController, final View view) {
            // Replace the indeterminate drawable with a static red ColorDrawable
            ProgressBar progressBar = (ProgressBar) view;
            progressBar.setIndeterminateDrawable(new ColorDrawable(0xffff0000));
            uiController.loopMainThreadUntilIdle();
        }
    });
}

Ответ 3

У меня подобная проблема. Тест завершился неудачно уже в первом вызове getActivity(). Таким образом, неопределенный перенос ProgressBar должен быть заменен после начала действия.

 Application application = (Application)this.getInstrumentation().getTargetContext().getApplicationContext();
    application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
        @Override
        public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
            //not here, it too early
        }

        @Override
        public void onActivityStarted(Activity activity) {
            //find the progressBar in your activity
            ProgressBar progressBar = ((ProgressBar) activity.findViewById(R.id.progress_bar));
            if(progressBar != null) {
                //replace progress bar drawable as not animated
                progressBar.setIndeterminateDrawable(new ColorDrawable(0xffff0000));
            }
        }

        @Override
        public void onActivityResumed(Activity activity) {

        }

        @Override
        public void onActivityPaused(Activity activity) {

        }

        @Override
        public void onActivityStopped(Activity activity) {

        }

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

        }

        @Override
        public void onActivityDestroyed(Activity activity) {

        }
    });

    //Now you can start the activity
    getActivity();

Ответ 4

Основываясь на решении Thomas R., другой подход заключается в том, чтобы изменить извлечение ProgressBar в тесте, чтобы избежать изменения производственного кода.

Пример:

    Activity activity = startActivity();

    // override progress bar infinite animation with a simple image
    ProgressBar progressBar = (ProgressBar) activity.findViewById(R.id.loading_progressbar);
    progressBar.setIndeterminateDrawable(activity.getDrawable(android.R.drawable.ic_lock_lock));

    // click on the button that triggers the display of the progress bar
    onView(withId(R.id.login_button)).perform(click());

Ответ 5

Этот ответ может быть запоздалым. С эспрессо вы должны отключить анимацию.

На вашем устройстве в разделе "Настройки" > "Параметры разработчика" отключите следующие 3 настройки:

Шкала анимации окон, масштаб анимации перехода, масштаб анимации аниматора

https://developer.android.com/training/testing/espresso/setup.html#set-up-environment

Есть ответ на тестовый индикатор выполнения на Android с эспрессо от riwnodennyk

Но будьте осторожны с UIAnimator

Внимание: мы рекомендуем тестировать ваше приложение с помощью UI Automator только тогда, когда ваше приложение должно взаимодействовать с системой для выполнения критического варианта использования. Поскольку UI Automator взаимодействует с системными приложениями и пользовательскими интерфейсами, вам необходимо повторите запуск и исправьте свои тесты Automation UI после каждого обновления системы. такие обновления включают обновления версии платформы Android и новые версии Службы Google Play. В качестве альтернативы использованию UI Automator мы рекомендуем добавлять герметичные тесты или отделять ваш большой тест на набор небольших и средних тестов. В частности, сосредоточьтесь на тестировании одного единый обмен сообщениями между приложениями, например, отправка информацию в другие приложения и ответы на результаты намерений. Инструмент Espresso-Intents может помочь вам написать эти более мелкие тесты.

https://developer.android.com/training/testing/fundamentals.html#large-tests