Давно хотела поделиться этим инструментом, и вот наконец дошли руки.
С чем сталкивается каждый автоматизатор в любом проекте, с которым ему приходится работать? Не знаю как вы, а я с тем, что любая операция на тестируемом окружении занимает какое-то время. При чем каждый раз это время разное.
Первое, чем страдают начинающие автоматизаторы — это Thread.sleep. Поищите у себя по проекту наличие этой строки? Если меньше 4 раз, мои позравления
Каждый раз мы пишем какие-либо костыли на тему того, чтобы подождать, пока что-нибудь произойдет, и каждый раз приходим к тому что либо тест долго ждет(потому что кто-то ждет фиксированное время), либо в тесте напрямую вызывается Thread.sleep (и это выглядит ужасно), либо так или иначе мы пишем какой-нибудь do_while цикл.
Мне очень понравился подход в проекте Selenium WebDriver, где вы изначально задаете максимальное время ожидания события, и частоту опрашивания системы (я имею в виду WebDriverWait).
На основе него я и построила один вспомагательный унифицированный инструмент (на базе Java8, так что кто еще не перешел, еще один пункт в список “почему стоит это вделать сейчас”), который позволяет ожидать либо обязательное событие, либо событие, которое может произойти, но если не происходит, то в целом тоже не страшно.
Код доступен в репозитории GitHub, по свободе перенесу в базу знаний сюда.
В чем основной смысл. Есть некая система А, которая должна делать любую операцию не дольше 5 секунд, иначе пользователь будет недоволен и уйдет.
Мы знаем, что операция f1+f2
занимает в среднем 1 секунду, чаще всего в диапазоне 0,5 секунд до 1,5 секунд, но очень редко дольше. Операция же func(f1, f2)
занимает около 2 секунд.
Тогда для ожидания результата первой операции мы можем создать ожидание сделующего вида: new Wait(5L, TimeUnit.SECONDS.toMilis(1))
. А для второй new Wait(5L, TimeUnit.SECONDS.toMilis(2))
. Это позволит оптимизировать время выполнения теста в некоторой степени, но чаще можно пожертвовать настолько точными определениями ради улучшения читаемости тестового кода и это упрощается до Wait imWait = new Wait(5L, TimeUnit.SECONDS.toMilis(2))
;
Теперь же есть два варианта развития событий:
- Я жду что статус какой-то операции точно вернет мне строку «Ok». Пусть эта операция отображена функцией:
public String getStatus(@NotNull Integer statusCode) {
return statusCode == 200 ? «Ok» : «Failure»;
}
тогда в коде тестов мне следует организовать ожидание следующим образом:
imWait.until(()→getStatus(someCode).equals(«Ok»));
Но если мы не дождемся, то ошибка будет не слишком читаемая
TimeoutException: Timed out after 1 seconds waiting for BasicConditionsTest$$Lambda$1/1607460018@3d012ddd
Но вот в таком случае:
@Test
public void waitForStatusTest() {
shortTime.until(status("Ok"));
}
public static Supplier<Boolean> status(final String status) {
return new Supplier<Boolean>() {
String current;
@Override
public String toString() {
return String.format("status to be %s, current is %s", status, current);
}
@Override
public Boolean get() {
current = getStatus(someCode);
return status.equals(current);
}
};
}
TimeoutException: Timed out after 1 seconds waiting for status to be Ok, current is Failure
Мне кажется, что если тесты будут падать с такими сообщениями, то и репорты будут красивее, да и разобраться, что же произошло с тестом, будет проще
- Я жду, что либо статус «Ok» и все абсолютно автоматически отработало и все хорошо, либо, если не «Ok», мне нужно сделать дополнительную операцию;
@Test
public void waitForStatusTest() {
if(!shortTime.possible(status("Ok"))){
do something
}
}
В проекте на гитхабе больше примеров, в том числе есть и многопоточные. Но если у вас возникнут вопросы зачем это нужно или как решить свою задачу с помощьюю этого механизма — прошу в комменты или в личку.