Эспрессо не ждет, пока активность не будет уничтожена, прежде чем создавать новую для следующего теста
Ситуация
В официальной документации здесь: https://google.github.io/android-testing-support-library/docs/rules/index.html говорится:
"Это правило обеспечивает функциональное тестирование одного действия. Тестируемое действие будет запускаться перед каждым тестом, аннотированным @Test, и перед любым методом, аннотированным @Before. Оно будет прекращено после завершения теста, а все методы аннотированы @After. завершены. Доступ к тестируемой активности можно получить во время теста, вызвав ActivityTestRule#getActivity()."
Технически да, Деятельность прекращается. Но, похоже, нет никаких гарантий относительно того, когда это произойдет. Например, это не обязательно произойдет, прежде чем он будет создан снова для следующего теста.
Эта проблема
В некоторых из моих тестов мне нужно полагаться на фрагменты OnDestroy или OnDetach, вызываемые после каждого теста, до начала следующего теста. У меня есть слушатели, которых нужно очистить и воссоздать.
Если onDestroy из предыдущего теста вызывается после OnResume в текущем тесте, тогда обратный вызов очищается, и представление не обновляется, и тест завершается неудачей.
Если onDestroy из предыдущего теста вообще не вызывается, то обратный вызов из текущего теста будет ссылаться на неправильный экземпляр. Снова представление не будет обновлено и тест не пройден.
Вопрос
- Это поведение обсуждается в данной ситуации по замыслу или это ошибка? Я до сих пор не могу найти это в документации.
- Как лучше всего справиться с этим? Я подозреваю, что другие люди столкнулись с этой проблемой.
Изменить: я теперь решил часть 2. См. Раздел обходных путей ниже. Однако, если кто-то может ответить на первую часть, сославшись на официальный ресурс, я был бы рад принять этот ответ. Это то, что я действительно спрашиваю здесь. Вторая часть была просто бонусом, если у кого-то были какие-то идеи.
Доказательство
Если вы хотите увидеть это поведение, это займет всего несколько минут. Создайте новый проект с деятельностью, подобной этой:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onResume() {
super.onResume();
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
и тестовый класс, как это:
@RunWith(AndroidJUnit4.class)
@LargeTest
public class EspressoLifecycleTest {
@Rule
public ActivityTestRule<MainActivity> mActivityRule =
new ActivityTestRule<>(MainActivity.class);
@Test
public void test1() {
}
@Test
public void test2() {
}
@Test
public void test3() {
}
@Test
public void test4() {
}
}
Установите точки останова на методы OnResume и OnDestroy и запустите набор тестов в режиме отладки.
Сделайте это несколько раз и обратите внимание, что порядок вызова методов жизненного цикла Activity не согласован. Например, он может вызывать OnResume дважды подряд, а затем вызывать OnDestroy один раз, затем OnResume дважды снова, а затем OnDestroy три раза или любую другую комбинацию, о которой вы только можете подумать. Конечно, он всегда начинается хотя бы с одного OnResume. Иногда он даже не вызывает OnDestroy, если он в самом конце, но это нормально. Что не хорошо, так это то, что мои тесты не очень удачные из-за этого непредсказуемого порядка.
Я знаю, что это может быть преднамеренным и может быть простой способ справиться с этим, мне просто не повезло найти его. Пожалуйста, если вы знаете, что это, отправьте ответ здесь. Мне все равно, насколько глупым может быть мой вопрос задним числом, я потратил много времени на эту проблему. Это почти всегда что-то простое, поэтому я готов быть смущен ответом.
обходные
Использование onPause поверх OnDestroy имеет побочный эффект при вызове, когда я запускаю ActivityForResult, но без повторного вызова onResume во фрагменте фона в режиме планшета. Я изучаю способы сделать эту работу, но пока нет решения.
Редактировать: onPause закончился с той же проблемой - отчасти поэтому я использовал onDetach в первую очередь. В конечном счете, бывают случаи, когда я не хочу отсоединять слушателей, пока фрагмент не будет уничтожен.
Это приводит меня к моей следующей идее, которая сработала! Ура! До сих пор я создавал обратный вызов для вызывающего Activity, для того, о чем он просил, только если этого конкретного обратного вызова не существовало. Оказывается, это была плохая идея. Я сделал это, чтобы ограничить количество обратных вызовов точным количеством. Мотивация была здравой, но реализация требовала полной очистки от обратных вызовов. Решение состоит в том, чтобы воссоздать каждый обратный вызов, когда бы он ни вызывался из фрагмента. Не создавайте его, если он нулевой, всегда создавайте его и заменяйте все, что было раньше. Теперь их вообще не нужно очищать (AFAIK).
2 ответа
Это ошибка: http://b.android.com/201513
Я использую форк работы вокруг этого: https://github.com/shazam/fork
Я заметил эту проблему раньше, и "решение", о котором я могу подумать, - переопределить методы в ActivityTestRule: afterActivityFinished () или beforeActivityLaunched (). В основном вы хотите проверить и подождать, пока слушатели будут очищены перед выполнением следующего теста.
ИМО, это ошибка ActivityTestRule.