2. МОТИВАЦИЯ
• Ваши автотесты постоянно валятся без
видимых причин
• Ваше приложение постоянно что-то
подгружает втихаря
• Ваше приложение не ожидает, что по
нему будут слишком уж быстро кликать
• Ваши автотесты проходят настолько
быстро, что вы не успеваете попить
кофе и хорошенько побраузать
3. ПРИМЕНИМОСТЬ
Используйте паттерн «Сон», чтобы:
• Подождать, пока какой-либо элемент появится на
странице
• Подождать, пока элемент исчезнет
• Подождать, пока у элемента изменится какой-нибудь
атрибут
• Подождать на случай, если элемент может появиться,
а может и нет
• Подождать, потому что иначе приложение тупо рухнет
• Просто подождать
5. УЧАСТНИКИ
• SleepService – «сервис сна»:
- определяет операцию sleep(), которая
позволяет осуществить процедуру ожидания.
Альтернативные наименования: pause(), wait() и т.п.
6. ОТНОШЕНИЯ
SleepService, как правило, не имеет смысла выделять в
отдельный класс. Вполне достаточно будет добавить
его функциональность в один или несколько из уже
существующих утилитных классов (возможно даже, с
применением интерфейса или абстрактного класса
CanSleep).
Клиенты получают доступ к процедуре сна через вызов
метод sleep().
7. РЕЗУЛЬТАТЫ
• Легко добавить ожидание в любой точке кода
• Любой компонент может при необходимости
приостановить свое выполнение
• Вызываемые автотестом методы исполняются
обстоятельно и без спешки
• Глядя на исполняющийся тест, можно по крайней
мере понимать, что он делает, и при этом успевать
заниматься прочими активностями
• Общее время выполнения тестовой сюиты
незначительно увеличивается за счет повышения
надежности тестов
8. РЕАЛИЗАЦИЯ
При реализации паттерна «Сон» необходимо рассмотреть
следующие вопросы:
• Сон должен блокировать выполнение теста
• Время сна должно быть можно конфигурировать
• Но должно быть можно инициировать сон и просто так,
не заморачиваясь на таймаутах
• Процедура сна должна быть масштабируемой
• В случае, если во время сна что-то пошло не так, об
этом надо куда-то сообщить
• Но в некоторых случаях можно особо из-за этого не
напрягаться
9. Простейшая реализация:
public static void sleep(long timeout) {
try {
Thread.sleep(timeout);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Плюсы: просто и элегантно.
Минусы: может засорять лог стектрейсами. Все равно
никто не знает, что с ними делать.
ПРИМЕРЫ КОДА
10. Улучшенная реализация:
public static void sleep(long timeout) {
try {
Thread.sleep(timeout);
} catch (InterruptedException e) { }
}
Плюсы: еще проще и элегантнее.
Минусы: отсутствуют.
ПРИМЕРЫ КОДА
11. ПРИМЕРЫ КОДА
Продвинутая реализация с генерацией исключения:
public static void sleep(long timeout) {
try {
Thread.sleep(timeout);
} catch (InterruptedException e) {
throw new RuntimeException(e.getMessage());
}
}
Плюсы: показывает, что вы не какие-нибудь там и умеете
генерировать исключения. Обратите внимание, блок throws не
требуется, так как это RuntimeException!
Минусы: исключение нужно где-то как-то обработать.
12. ПРИМЕРЫ КОДА
Продвинутая реализация с логированием предупреждения:
public static void sleep(long timeout) {
try {
Thread.sleep(timeout);
} catch (InterruptedException e) {
LOGGER.warn("sleep() method was interrupted.", e);
}
}
Плюсы: обработка исключения на более высоком уровне больше не требуется!
Минусы: нужно инициализировать логгер. Засоряет лог предупреждениями,
которые все равно никто не читает.
13. ПРИМЕРЫ КОДА
Продвинутая реализация с таймаутом по умолчанию:
private static final long DEFAULT_TIMEOUT = 15000;
public static void sleep() {
sleep(DEFAULT_TIMEOUT);
}
Плюсы: не надо думать о величине таймаута.
Минусы: отсутствуют.
14. МАСШТАБИРУЕМОСТЬ
Иногда необходимо выполнить ожидание в течение
нестандартного отрезка времени. Как же сделать, чтобы
процедура сна была масштабируемой?
public void clientMethod() {
…
SleepService.sleep(sleepTime * 8);
…
}
Это решение в лоб, очевидно, не годится, так как неприменимо для
случая вызова метода sleep() без параметров. Как же быть?
15. МАСШТАБИРУЕМОСТЬ
Все очень просто!
public void clientMethod() {
…
SleepService.sleep(sleepTime);
SleepService.sleep(sleepTime);
SleepService.sleep(sleepTime);
SleepService.sleep(sleepTime);
SleepService.sleep(sleepTime);
SleepService.sleep(sleepTime);
SleepService.sleep(sleepTime);
SleepService.sleep(sleepTime);
…
}
16. АЛЬТЕРНАТИВЫ
Рассмотрим другие, неправильные, альтернативы решения
проблемы:
• [Решение] Реализовать процедуру «поллинга», т.е.
опроса элементов в цикле на предмет достижения
требуемого условия.
• [Ответ] Но это же неэффективно! Вместо того, чтобы
спокойно поспать, автотест должен постоянно
обрабатывать какие-то инструкции, делать запросы,
анализировать результаты и т.п. Все это негативно
сказывается на сроке службы процессора. Кроме того, в
этом случае автотест не полностью эмулирует действия
пользователя, который, как известно, никакие элементы
не опрашивает, а тупо залипает в экран, пока страница
грузится. Именно эту активность пользователя и
эмулирует шаблон проектирования «Сон».
17. АЛЬТЕРНАТИВЫ
• [Решение] Попросить разработчиков встроить
механизмы синхронизации загрузки страниц и
защиты от так называемого «happy clicking».
• [Ответ] Непрофессионально! Вы - автоматизаторы
тестирования, а не какие-нибудь там молокососы,
бегающие с просьбами к разработчикам. Вы вполне в
состоянии справиться с проблемой без постороннего
вмешательства.