Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- src / test / java / com / tasj / modular_opp / search / GoogleSearchTest.java
- src / main / java / com / tasj / modular_oop / search / GoogleSearch.java
- /*
- корректнее назвать пекеджи search - googlesearch
- или структурно
- google
- search
- gmail
- */
- ****************************************
- public interface Condition<V> {
- public abstract V apply(By locator);
- }
- /*
- public abstract - лишнее
- мы в интерфейсах - лишь объявляем методы
- и в классах их будем имплементировать как public
- так что тут
- вместо
- public abstract V apply(By locator);
- достаточно
- V apply(By locator);
- */
- *********************************
- public class MinimumSizeOf implements Condition<Boolean> {
- /*
- я бы не реализовывала Condition<Boolean>
- на самом деле, любой из кондишенов - можно реализовать
- либо как
- Condition<WebElement>
- либо как
- Condition<List<WebElement>>
- т к по сути - мы всегда - работаем либо со списком, либо с элементом
- мы мало выгод получаем от реализации Condition<Boolean>
- сам факт - что проверка кондишена не упала - говорит о том, что да , все ок
- да и вот такой вариант - Condition<Boolean>
- будет требовать дополнительной логики в WaitFor#until
- (мы же не нулл вовращаем в apply, а FAlSE)
- можешь сама посмотреть в селениумском WevDriverWait#until
- предлагаю не тратить силы на развитие логики в WaitFor#until
- а кондишены реализовать как Condition<WebElement> или Condition<List<WebElement>>
- это полезнее)
- */
- *****************************************
- public class NthElementText implements Condition {
- /*
- этот - реализуй как Condition<List<WebElement>>
- это несколько странно)
- но пока так реализуй)
- логичнее реализовать - чтоб на вход - мы получали локатор списка
- а возвращали - вебэлемент
- но - это будет нарушать общую картинку)
- остальные кондишены - если и получают локатор списка - возвращают список
- если локатор элемента - возвращают элемент
- пока по кондишены для todoMVC не думай)
- они тоже, такие, гибридные)
- мы вскоре и от этого NthElementText избавимся)
- пока - пусть будет Condition<List<WebElement>>
- вернем в случае успеха - тот же список элементов, что и получили
- */
- ******************************
- public class Size implements Condition {
- /*
- вообще во всех кондишенах - уточни тип у Condition
- Condition<WebElement> либо Condition<List<WebElement>>
- */
- ********************************
- public class Url implements Condition {
- /*
- а вот такой кондишен не стоит реализовывать)
- странно оперировать локатором - для проверки урла
- это проверяй как и ранее - через родной селениусмский кондишен
- можно оставить для этого - ранее реализованный assertThat
- за счет разных параметров - конфликтовать с новыми assertThat - старый assertThat не будет )
- */
- ****************************
- public static <V> V assertCondition(Condition<V> condition){
- return waitFor(null).until(condition);
- }
- /*
- и вот этот метод со странной реализацией - уйдет )
- */
- *************************************
- public static WaitFor waitFor(By locator, long timeout){
- /*
- я бы параметр timeout - перенесла в until
- а в этом методе - оставила только локатор
- мне кажется это более логичным
- для какого элемента/списка ждем
- до каких пор ждем = кондишен + таймаут
- как-то более последовательно)
- */
- ************************************
- catch (StaleElementReferenceException | IndexOutOfBoundsException | ElementNotVisibleException ex) {
- System.out.println(locator);
- }
- /*
- посмотри - какие предки есть у исключений
- все кроме IndexOutOfBoundsException
- приводятся к WebDriverException
- можно ловить именно его - WebDriverException (его потомков мы так тоже поймаем)
- и IndexOutOfBoundsException
- выводить это - System.out.println(locator);
- в общем-то мало полезно
- а вот запомнить полученную ошибку в переменную
- и затем передать ее вторым параметром в TimeoutException - будет самое то
- в таком случае - сообщение об ошибке будет вот такое
- наше сообщение
- caused by ... и описание исключения - причины
- такую переменную назови lastError
- используй тип Throwable
- http://howtodoinjava.com/best-practices/java-exception-handling-best-practices/
- http://www.developer.com/java/data/best-practices-in-java-exception-handling.html
- https://www.javacodegeeks.com/2013/07/java-exception-handling-tutorial-with-examples-and-best-practices.html
- https://habrahabr.ru/company/golovachcourses/blog/225585/
- */
- *************************
- (new TimeoutException("failed while waiting " + timeout + " seconds to assert " + condition.toString())).printStackTrace();
- return null;
- /*
- нам нужно вызвать исключение
- нам нужно - чтоб тест упал) - если проверка не прошла
- это делается так - throw new TimeoutException(....)
- линки выше - помогут разобраться получше)
- */
- ****************************************************
- /*
- Иерархия для кондишенов у тебя сейчас - достаточно простая
- интерфейс
- и классы-кондишены, имплементирующие его
- Минимально необходимая реализация есть
- Будем ее развивать
- Далее - реализуй абстрактный класс-предок AbstractCondition<V> ,
- который имплементирует интерфейс Condition<V>
- Статья про нейминг
- http://www.vertigrated.com/blog/2011/02/interface-and-class-naming-anti-patterns-java-naming-convention-tautologies/
- Теперь смотрим дальше
- Нам хочется, чтобы наш toString() для любого кондишена был хорошо структурирован
- Это значит, чтобы фразы были типа
- __имя кондишена__ +
- for ____element/elements___ found by: ___locator___
- expected ___expected result description_____
- actual ____actual result description_____
- Можно конечно в каждом из кондишенов просто строить такую фразу
- согласно правилу
- А можно - toString() реализовать в абстрактном классе, и внутри этого метода - вызывать абстрактные методы
- а их уже - реализуем в потомках. Таким образом - структура сообщения любого из кондишенов
- будет одинаковой
- где брать ___locator___ тут - мы чуть позже поговорим...
- пока пропусти этот момент
- а вот для
- ____element/elements___
- ___expected result description_____
- ____actual result description____
- объяви и используй абстрактные методы
- identity()
- expected()
- actual()
- __имя кондишена__
- раз мы будем реализовывать кондишены как отдельные классы - потомки (пока - нашего абстрактного класса)
- то откуда взять имя кондишена - у нас есть
- у нас есть имя класса кондишена - чем не имя )
- Далее
- element/elements
- Это только верхушечка айсберга
- Да, схема проверки кондишенов - у нас одна и та же
- Хоть это кондишен для списка элементов
- Хоть для элемента
- И нам нужно, чтоб наш waitUntil был один и работал с любым кондишеном
- Но
- Нам важна разница - что это за кондишен - для элемента или коллекции
- В данный момент - чтобы сказать про то в фразе - for ____element/elements
- А далее (в следующих заданиях) - чтобы кондишены для element - мы просто НЕ МОГЛИ применить к elements
- Таким образом, приходим к тому, что у нашего общего предка AbstractCondition<V>
- Будут 2 абстрактных потомка
- CollectionCondition extends AbstractCondition<List<WebElement>>
- ElementCondition extends AbstractCondition<WebElement>
- От которых мы будем наследовать наши реальные кондишены
- И тогда, стоит держать 2 класса для реализации статических методов - вызовов кондишенов
- CollectionConditions и ElementConditions
- это будут классы-контейнеры статических методов
- типа
- public static Condition<WebElement> visible() {
- return new Visible();
- }
- чтобы уже в коде - не писать - new Visible()
- С иерархией разобрались немного )
- Возвращаемся к фразе в toString()
- Если этот метод реализовать в главном предке AbstractCondition,
- и этот метод будет использовать абстрактные методы, возвращающие строки
- для всех элементов этой фразы
- То структура сообщения о кондишене - будет всегда четкой
- А нам останется - реализовать эти абстрактные методы, возвращающие строки
- в потомках
- Тут смотри внимательно
- Некоторые из методов надо будет реализовать уже в кондишенах-потомках
- Некоторые - в CollectionCondition и ElementCondition
- Руководствуйся такими рассуждениями
- Если во всех потомках я пишу одинаковый код
- То лучше этот код написать в предке
- Что касается типа параметра condition для
- until(Condition<V> condition)
- Ты можешь указать интерфейс Condition<V>
- И метод будет корректно работать для любого из кондишенов
- Т к этот интерфейс лежит в основе этой иерархии
- */
- ****************************************
- /*
- еще один наворот внутри кондишенов)
- мы его впоследствии переделаем
- сейчас нам это нужно для лучшего понимания процесса
- в apply передают локатор
- описание которого мы возвращаем в одном из методов кондишена (для ToString)
- и это - справедливо для всех кондишенов
- и нам - еще в AbstractCondition интересно сохранить этот локатор
- потому в AbstractCondition заводим переменную locator
- и реализуем метод apply
- в котором
- сохраняем переданный в apply локатор
- и вызываем абстрактный метод check
- (- который, собственно, и нужно будет в кондишенах реализовывать вместо apply)
- check - будет делать то же, что и apply делал ранее
- нам это нужно было для того, чтоб локатор получить еще на уровне абстрактного класса
- теперь - и в toString - мы можем подправить фразу - про локатор
- сразу подумай, какой модификатор доступа использовать для такой переменной
- http://www.quizful.net/interview/java/access-modifiers
- но это опять была только верхушка айсберга)
- посмотри на реализованные кондишены
- первой строкой в методе проверок - у тебя идет
- List<WebElement> elements = getDriver().findElements(elementsLocator);
- или
- WebElement element = getDriver().findElement(elementsLocator);
- (таких, кстати, пока нету
- реализуй
- visible
- present
- text
- exactText
- )
- Так вот
- фактически - вот это
- List<WebElement> elements = getDriver().findElements(elementsLocator);
- или
- WebElement element = getDriver().findElement(elementsLocator);
- это сущность типа V с точки зрения класса AbstractCondition
- давай метод check изменим
- пусть принимает не локатор
- а уже V entity (т е внутри кондишена в реализации check
- нам ничего не придется искать по локатору - нам это уже на вход передадут)
- а вот в реализации apply в AbstractCondition
- для получения этого V entity
- мы объявим новый абстрактный метод getWrappedEntity()
- который будет нам возвращать значение типа V
- а реализуем его в классах CollectionCondition и ElementCondition
- думаю, ты догадаешься, как )
- а вот потом, когда у нас будут наши классы для элементов (следующее задание)
- мы будем в apply передавать не локатор
- а сам элемент нашего нового класса
- и сам элемент будет возвращать getWrappedEntity()
- и мы тут, в кондишенах, избавимся от getWrappedEntity() и его реализаций )
- пока это такой костыль
- нарушающий принцип Single Responsibility
- но позволяющий нам сейчас максимально реализовать код
- который впоследствии изменим минимально
- */
Advertisement
Add Comment
Please, Sign In to add comment