Тестирование индикатора выполнения на Android с помощью Espresso
Рабочий процесс должен быть следующим:
- Деятельность начинается
- Прогресс-бар виден
- Сетевой запрос срабатывает (ресурс холостого хода уже зарегистрирован, поэтому эспрессо знает, как его ждать).
- Индикатор выполнения скрыт
- Текст из сети отображается.
До этого момента я написал утверждения для шагов 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()));
}