Тестирование индикатора выполнения на Android с помощью Espresso

Рабочий процесс должен быть следующим:

  1. Деятельность начинается
  2. Прогресс-бар виден
  3. Сетевой запрос срабатывает (ресурс холостого хода уже зарегистрирован, поэтому эспрессо знает, как его ждать).
  4. Индикатор выполнения скрыт
  5. Текст из сети отображается.

До этого момента я написал утверждения для шагов 1, 3, 5, и он отлично работает:

onView(withText("foo 1"))
    .check(matches(isDisplayed()));

Проблема в том, что я понятия не имею, как сообщить эспрессо, чтобы проверить видимость индикатора выполнения перед выполнением запроса и после его выполнения.

Рассмотрим onCreate() метод заключается в следующем:

super.onCreate(...);
setContentView(...);

showProgressBar(true);
apiClient.getStuff(new Callback() {
    public void onSuccess() {
        showProgressBar(false);
    }
});

Я пробовал следующее, но это не работает:

// Activity is launched at this point.
activityRule.launchActivity(new Intent());

// Up to this point, the request has been fired and response was 
// returned, so the progress bar is now GONE.
onView(withId(R.id.progress_bar))
   .check(matches(isDisplayed()));

onView(withId(R.id.progress_bar))
    .check(matches(not(isDisplayed())));

Причина, по которой это происходит, заключается в том, что, поскольку клиент зарегистрирован в качестве ресурса в режиме ожидания, эспрессо будет ждать, пока он снова не будет работать, прежде чем запустить первый onView(...progressbar...)... поэтому мне нужен способ, чтобы эспрессо знал, что он ДОЛЖЕН работать без дела.

РЕДАКТИРОВАТЬ: это тоже не работает:

idlingResource.registerIdleTransitionCallback(new IdlingResource.ResourceCallback() {
        @Override
        public void onTransitionToIdle() {
            onView(withId(R.id.progress_bar))
                    .check(matches(isDisplayed()));
        }
    });

3 ответа

Эспрессо имеет проблемы с анимацией. Вы можете просто установить рисование индикатора выполнения на что-то статичное только для теста, и оно будет работать как положено.

Drawable notAnimatedDrawable = ContextCompat.getDrawable(getActivity(), R.drawable.whatever);
((ProgressBar) getActivity().findViewById(R.id.progress_bar)).setIndeterminateDrawable(notAnimatedDrawable);

onView(withId(R.id.progress_bar)).check(matches(isDisplayed()));

Как я вижу Espresso тесно связан с пропуском динамических действий пользовательского интерфейса, поэтому вы не можете проверить ProgressBar с помощью Espresso, Тем не менее, вы можете легко сделать это с помощью другого инструмента Google Android: UiAutomator следующим образом:

    saveButton().click(); // perform action opening ProgressBar with UiAutomator, not Espresso
    assertTrue(progressBar().exists());

Используя эти статические утилиты:

public static UiObject progressBar() {
    return uiObjectWithText(R.string.my_progress);
}

public static UiObject saveButton() {
    return uiObjectWithId(R.id.my_save_button);
}

public static UiObject uiObjectWithId(@IdRes int id) {
    String resourceId = getTargetContext().getResources().getResourceName(id);
    UiSelector selector = new UiSelector().resourceId(resourceId);
    return UiDevice.getInstance(getInstrumentation()).findObject(selector);
}

public static UiObject uiObjectWithText(@StringRes int stringRes) {
    UiSelector selector = new UiSelector().text(getTargetContext().getString(stringRes));
    return UiDevice.getInstance(getInstrumentation()).findObject(selector);
}

Убедитесь, что ваш build.gradle включает в себя:

androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'

Похоже, это не может быть действительно возможным. Хотя это и более старая групповая публикация, в обсуждении Android Test Kit есть довольно решительный ответ, в котором говорится, что потоки пользовательского интерфейса не отдыхают во время анимации индикаторов выполнения, и поэтому платформа Espresso не может выполняться.

Маркус Клепп рекомендует продвигаться дальше, используя типы сборок. Плагин Gradle позволит вам определять различные типы сборки. Вы можете настроить другой макет в вашем androidTest тип сборки, который заменяет View под вопросом что-то общее. Если все, что вы делаете, это подтверждает, что виджет isDisplayed() при одном наборе условий и not(isDisplayed()) при другом наборе условий, тогда вы наверняка могли бы реализовать это через другие файлы макета. Не то чтобы это не было чем-то вроде лифта.

Наконец, здесь может быть еще один пост, в котором содержится некоторая дополнительная информация: "java.lang.RuntimeException: не удалось запустить намерение" для пользовательского интерфейса с неопределенным ProgressBar

В моем случае решение, которое было предоставлено выше, также работает, но я упрощаю его, поэтому добавил build.gradle библиотека uiautomator

androidTestImplementation 'com.android.support.test.uiautomator:uiautomator-v18:2.1.3'

и создал новый класс, который будет работать, например, с индикатором выполнения

public class ProgressBarHandler {

public static void waitUntilGoneProgressBar() {
    progressBar().waitUntilGone(10000);
}

private static UiObject progressBar() {
    return uiObjectWithId(R.id.progress_bar);
}

private static UiObject uiObjectWithId(@IdRes int id) {
    String resourceId = getTargetContext().getResources().getResourceName(id);
    UiSelector selector = new UiSelector().resourceId(resourceId);
    return UiDevice.getInstance(getInstrumentation()).findObject(selector);
}

}

и в моих тестах используют все методы Espresso, а при необходимости только тогда обращаются к UiAutomator в тестах, например

public class LoginTest extends AbstractTest {

@Rule
public ActivityTestRule<LoginActivity> createAccountActivityTestRule = new ActivityTestRule<>(LoginActivity.class);

@Test
public void loginTest() {
    onView(withId(R.id.login_email)).perform(typeText("autotest666@gmail.com"));
    onView(withId(R.id.input_password)).perform(typeText("Password123."));
    onView(withId(R.id.login_log_in)).perform(click());
    waitUntilGoneProgressBar();
    onView(withId(R.id.fragment_home_title)).check(matches(isDisplayed()));
}
Другие вопросы по тегам