Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- http://joxi.ru/E2pdR1lFBdXng2
- /*
- лишнее есть в репозитории
- скорей всего добавил - перед созданием .gitignore
- https://help.github.com/articles/removing-a-remote/
- http://stackoverflow.com/questions/7927230/remove-directory-from-remote-repository-after-adding-them-to-gitignore
- http://stackoverflow.com/questions/13541615/how-to-remove-files-that-are-listed-in-the-gitignore-but-still-on-the-repositor
- https://git-scm.com/docs/git-rm
- */
- ***********************
- *****************************
- public abstract class OwnCondition<T> {
- public abstract T apply(By locator);
- }
- ...
- public class CustomConditions {
- public static OwnCondition<WebElement> nthElementHasText(final int index, final String text) {
- ....
- public static <V> OwnCondition<V> elementExceptionsCatcher(final OwnCondition<V> condition) {
- /*
- давай для начала - чуть упростим)
- избавимся от кетчера
- то, что мы ловили с кетчере - мы спокойно можем ловить и в ConciseAPI#waitUntil
- завернем apply в try-catch - и можно убирать кетчера
- далее
- реализуем кондишены не как не объекты анонимного класса
- а так
- отдельно - классы-кондишены
- а в CustomConditions - методы будут создавать объекты вот тех, отдельно реализованных классов-кондишенов
- прибавится порядка в CustomConditions - кода станет меньше и и он будет проще
- будут еще положительные моменты от этого
- но это мы сможем оценить чуть позже в полном объеме)
- еще - посмотри на наш абстрактный класс OwnCondition
- раз мы на его уровне ничего не реализуем - мы можем объявить его как интерфейс
- и далее - уже классы-кондишены имплементировать от этого интерфейса
- собственно - для этого интерфейсы и объявляют
- чтобы разные классы, которые имплементируют интерфейс -
- оперировали одними и теми же методами
- и мы могли, объявив переменную типа интерфейс - работать с объектом любого из таких классов
- полезные линки по интерфейсам
- http://kostin.ws/java/java-abstract-and-interfaces.html
- http://developer.alexanderklimov.ru/android/java/interface.php
- https://docs.oracle.com/javase/tutorial/java/concepts/interface.html
- Статья про нейминг - интерфейсы + классы
- http://www.vertigrated.com/blog/2011/02/interface-and-class-naming-anti-patterns-java-naming-convention-tautologies/
- http://stackoverflow.com/questions/1932247/abstract-classes-and-interfaces-best-practices-in-java
- http://joxi.ru/E2pdR1lFB1pyM2
- Будет ОК - назвать интерфейс Condition
- В Selenium такое имя не используется, так что ок будет
- */
- public class ConciseAPI {
- ...
- public static <V> V waitUntil(By locator, OwnCondition<V> condition, long timeout) {
- long endTime = System.currentTimeMillis() + timeout;
- for( ;endTime > System.currentTimeMillis(); ) {
- /*
- while - тут был бы нагляднее
- http://developer.alexanderklimov.ru/android/java/while.php
- */
- V result = condition.apply(locator);
- if (result != null) {
- return result;
- }
- try {
- sleep(100);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- /*
- вот эту try-catch секцию - реализуй как отдельный метод sleep
- и тут вызывай
- вот эта цифра - 100 миллисекунд - это тоже лучше настраивать
- вынеси в Configuration - и эту переменную
- */
- }
- return null;
- /*
- если мы прождали-пропроверяли в течение всего таймаута
- и проверка не прошла - нам не нулл нужно вернуть
- нам нужно обеспечить - чтоб тест упал
- разумно использовать исключение селениумское - TimeOutException
- его нужно вызвать и в качестве параметра конструктора - передать сообщение об ошибке
- именно это сообщение мы и увидим - когда тест упадет на проверке
- вот такое сообщение - будет достаточно информативным
- failed while waiting ... seconds
- to assert ...(описание кондишена)
- 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/
- проверяй работу waituntil и кондишенов - на двух вариантах кода
- когда проверка должна пройти
- когда она не должна пройти
- и плюс к этому - когда проверка не должна пройти - смотри на сообщение об ошибке
- */
- }
- ************************************************************
- /*
- Иерархия для кондишенов у тебя сейчас - достаточно простая
- интерфейс
- и классы-кондишены, имплементирующие его
- Минимально необходимая реализация есть
- Будем ее развивать
- Далее - реализуй абстрактный класс-предок 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>
- И метод будет корректно работать для любого из кондишенов
- Т к этот интерфейс лежит в основе этой иерархии
- */
Advertisement
Add Comment
Please, Sign In to add comment