Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import static com.tasj.modularoop.core.conditions.ElementConditions.text;
- public class Texts extends CollectionCondition {
- ...
- @Override
- public List<WebElement> check(List<WebElement> entity) {
- /*
- не уровне AbstractCondition - назвать параметр entity - самое точное
- а тут было бы точнее - elements
- не требуется - чтобы имя параметра совпадало в методе, объявленном или реализованном в предке
- и в стоде, реализованнои или перереализованном в потомке
- главное - чтоб сигнатуры этого метода были одинаковы (тип возвращаемого значения, набор и типы параметров)
- просмотри все кондишены (и CollectionCondition, и ElementCondition)
- подправь имя этого параметра при необходимости
- но это так, по пути красоту наводим
- */
- ...
- for (String expectedText : expectedTexts) {
- if (text(expectedText) == null) return null;
- /*
- а вот такой вариант - не верный
- что есть ElementConditions.text
- это метод возвращающий кондишен
- (мы не делаем проверку, мы возвращаем объект-кондишен, который в любом случае - не равен нулл -
- посмотри на реализацию ElementConditions.text)
- как бы ни было соблазнительно - тут не переиспользовать ElementConditions.text или его методы
- и так код получится достаточно простым
- тут не стоит выискивать - как переиспользовать ElementConditions.text
- идеально - каждый из разработанных кондишенов - проверять в 2-ух режимах
- когда долна проверка пройти
- и конгда должна упасть
- проверка должна себя вести предсказуемо
- и сообщение об ошибке - должно быть на
- */
- ************************************
- public interface LazyEntity<V>
- public interface Element extends LazyEntity<WebElement>
- public class LazyElement implements Element
- /*
- развиваем и чуть подправляем структуру
- у нас - будет несколько классов - лейзи-элементов и лейзи-коллекций
- все лейзи-элементы - должны будут уметь делать - один и тот же перечень действий
- и аналогично - про лейзи-коллекции
- логично использовать для лейзи-элементов и лейзи-коллекций
- интерфейс (потомок LazyEntity)
- тут объявляем все методы-действия
- абстрактный класс
- тут реализуем все одинаковое
- потомки -
- тут реализуем только то, что отличает различные классы друг от друга
- конструктор + необходимые поля
- toString
- getWrappedEntity
- эти новые интерфейсы логично назвать LazyElement & LazyCollection
- абстрактные классы - AbstractLazyElement & AbstractLazyCollection
- и конечные классы - будут иметь более детальные имена
- (Lazy+откуда+уточнение+Element или Lazy+откуда+уточнение+Collection)
- при таком нейминге - мы учитываем конвеншенсы (про это они тоже есть)
- ниже дам линки
- с классами-лейзи-элементами
- как у нас будут обстоять дела
- лейзи-элементы любого вида - должны уметь то - что описано в interface LazyElement
- но - получать вебелемент мы будем - по-разному (фактически - реазицация getWrappedEntity)
- например
- мы уже реализовали - getWebDriver().findElement(locator)
- а будет еще и такой вариант - получить вебэлемент - для такого лейзи-элемента
- lazyElement.find(".destroy")
- lazyCollection.find(cssClass("edited"))
- lazyCollection.get(3)
- т е - в итоге - у нас будет несколько классов, имплементирующих interface LazyElement
- причем - отличаться у них будут лишь конструкторы и реазицация getWrappedEntity (ну и toString)
- а реализация остальных методов, да и вообще набор методов - один-в-один
- вот и получим такую иерархию
- самый общий интерфейс
- LazyEntity<T>
- его потомки - интерфейсы
- LazyElement
- LazyCollection
- абстрактные классы
- AbstractLazyElement
- AbstractLazyCollection
- (реализуем все методы, кроме абстрактного getWrappedEntity,
- ну и конструктор нам тут не нужен - т к класс абстрактный)
- набор классов - для элементов и коллекций
- наши уже разработанные варианты
- LazyWebDriverElement
- LazyWebDriverCollection
- (WebDriver = откуда, см схему в нейминге - выше писала)
- список будет пополняться)
- получишь что-то такое http://joxi.ru/GrqLOX3SNZPLoA
- пока закрасила те классы - которые еще у нас не появились)
- ну и разумно - это в рамках core - выделить в отдельный пекедж
- wrappers или entities - хорошее общее название
- т к вот эти наши классы - это лишь обертка вокруг вебэлемента/списка вебэлементов
- есть конвеншенсы и по этому поводу - какие имена давать интерфейсу, какие - абстракному предку,
- какие - классам-потомкам
- статья про это (лучший вариант)
- http://www.vertigrated.com/blog/2011/02/interface-and-class-naming-anti-patterns-java-naming-convention-tautologies/
- еще полезные линки
- http://stackoverflow.com/questions/2814805/java-interfaces-implementation-naming-convention
- https://web.archive.org/web/20130331071928/http://isagoksu.com/2009/development/java/naming-the-java-implementation-classes
- http://programmers.stackexchange.com/questions/152759/should-i-add-an-abstract-prefix-to-my-abstract-classes
- Interfaces, abstract classes - good practice
- http://stackoverflow.com/questions/1932247/abstract-classes-and-interfaces-best-practices-in-java
- http://joxi.ru/E2pdR1lFB1pyM2
- */
- ***************************
- public interface Element extends LazyEntity<WebElement>{
- ...
- Element shouldHave(Condition<WebElement> condition);
- Element should(Condition<WebElement>... conditions);
- /*
- should, shouldHave, shouldBe - лучше реализовать как синонимы = с онинаковой сигнатурой и функциональностью
- параметры (Condition<WebElement>... conditions) - обеспечат возможность работать как с одним кондишеном, так и с неколькими
- потому вариант с параметром (Condition<WebElement> condition) - не нужен
- касается и коллекции
- */
- ******************************
- public class LazyElement implements Element {
- private By locator;
- public LazyElement(By locator) {
- public WebElement getWrappedEntity() {
- public String toString(){
- /*
- вот это - уйдет уже к реализацию класса-потомка LazyWebDriverElement
- а остальное - останется в абстрактном классе
- заметь - в австрактном классе - не конструктор не нужен
- мы же не создаем объекты абстрактного класса)
- */
- @Override
- public Element clear() {
- /*
- тут тоже надо дождаться видимости и вызвать у вебэлемента метод clear
- */
- **********************************************
- public class LazyCollection implements ElementCollection {
- ...
- @Override
- public Element get(int index) {
- /*
- крутая) - додумалась до важного)
- в целом все верно, предвосхитила следующую работу)
- единственное - раз у нас уже все по полочкам
- то давай тут обойдемся пока без анонимных классов
- а реализуем отдельный класс LazyCollectionNthElement (тоже потомок AbstractLazyElement)
- и тут - будем создавать объект вот такого типа
- тут = в классе-абстрактной коллекции
- тут тоже - общую для коллекций логику - оставь в абстрактном классе
- а в потомках - будет только отличительное
- */
- *****************************
- *
- следующий наворот )
- WebElement - это тоже интерфейс
- Если мы отнаследуем наш интерфейс LazyElement от WebElement
- Это то же самое что и заявить - "наш LazyElement - полная замена WebElement - и везде где вы его использовали
- вы теперь можете использовать наш лейзи враппер
- который помимо всех фич вебэлемента еще и будет ждать себя..."
- конечно, можно было бы абстрактный класс реализовать имплементирующим два интерфейса
- Класс может быть реализован от нескольких интерфейсов
- но тогда, при использовании переменной типа LazyElement - мы не получим функциональности WebElement
- потому тут правильнее именно отнаследовать LazyElement от WebElement
- Это в java-ООП мире достаточно прикольная практика -
- всегда, когда ты хочешь сделать какие-то штуки внутри объекта публичными -
- выносить их сначала в отдельный интерфейс - и потом его имплементировать
- потому что просто сделать какие-то штуки публичными - это недостаточно "строго"
- если ты четко заявляешь - мой объект поддерживает такие-то интерфейсы, тогда
- все могут общаться с твоим объектом через четко прописанное API этого интерфейса
- тут надо внимательно к вопросу подойти)
- в рамках LazyElement - не реализовывай методов, одноименных с методами WebElement
- да, мы для некоторых методов потерям chainable возможности
- но зато не будет двусмысленностей
- в абстрактном классе AbstractLazyElement - реализуй все вебэлементовские методы
- думаю, проблем с этим не будет
- думай - в каких методах и чего надо ждать - ничего не ждать / ждать видимости / ждать наличия в DOM
- для проверки наличия в DOM - реализуй кондишен present
- */
- ****************************************
- /*
- следующий наворот )
- наворачиваем Collection )
- наследуем этот интерфейс и от Iterable<LazyElement>
- цель - уметь писать такой код
- elements = $$(...);
- for(LazyElement element:elements) {
- ...
- }
- т е уметь обходить нашу коллекцию элементов в таком варианте цикла
- чистая теория
- http://tutorials.jenkov.com/java-generics/implementing-iterable.html
- нам она практически не пригодится )
- просто для понимания - разумно ознакомиться
- достаточно понять, что
- при имплементировании интерфейса Iterable<...>
- надо будет реализовать метод
- public Iterator<ProxyElement> iterator()
- Дальше мы схитрим)
- List<...> тоже наследник Iterable<...>
- если мы внутри метода iterator()
- создадим и заполним список list типа List<LazyElement> элементами из коллекции
- то тогда можно вернуть в качестве результата метода iterator() - list.iterator();
- загвоздка в том, что в коллекции getWrappedEntity() возвращает значение типа List<WebElement>
- а мы хотим получить List<LazyElement>
- Вот и пришло время создать еще одного потомка для AbstractLazyElement
- назовем его LazyWrappedWebElement (обернутый веб элемент)
- будем передавать ему в конструктор вебЭлемент
- как ты понимаешь, его реазизация getWrappedEntity() - будет возвращать тот же веб элемент
- И теперь опять возвращаемся к методу iterator()
- Если в новый список List<LazyElement>
- Ты будешь складывать новосозданные объекты типа LazyWrappedWebElement
- То это будет ОК (т к LazyWrappedWebElement - потомок абстрактного класса который имплементирует интерфейс LazyElement)
- Проверяем новую функциональность на коде типа
- for (LazyElement element:tasks) {
- System.out.println(element.getText());
- element.shouldHave(text("а"));
- }
- */
Advertisement
Add Comment
Please, Sign In to add comment