julia_v_iluhina

Untitled

Oct 7th, 2016
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 22.26 KB | None | 0 0
  1. вопросы: я не уверен насчет всех этих выводов ошибок.
  2. Не пойму, как оно должно ложиться )
  3. Вот например, элемент не найден - http://joxi.ru/EA4vwLyfDeYy4m вообще ниче не ясно в выводе.
  4. а вот ошибка "не совпадает текст" - http://joxi.ru/n2Y5EgPTjgaBN2 - тут все окее
  5.  
  6.  
  7. public class WaitFor<V> {
  8.  
  9. ...
  10.     public V until(Condition<V> condition, long timeout) {
  11.    ...
  12.         do {
  13.             try {
  14.                 V result = condition.apply(smartEntity);
  15.                 ...
  16.                 } catch (IndexOutOfBoundsException | WebDriverException e) {
  17.                 lastError = e;
  18.             }
  19.             sleep(Configuration.pollingInterval);
  20.         }
  21.         while (System.currentTimeMillis() - startTime < timeout);
  22.  
  23.         throw new TimeoutException(String.format("Assert failed while waiting '%s' seconds " +
  24.                                                  "\n to assert: %s", timeout / 1000, condition.toString()), lastError);
  25.     }
  26. /*
  27.  
  28.     не смогла получить ошибку как на http://joxi.ru/EA4vwLyfDeYy4m
  29.     думаю, она проявлялась раньше - когда вот тут - мы не ловили такого эесепшена
  30.     сейчас - ловим и его предка тоже -  WebDriverException
  31.     потому - и видим красивое Assert failed while waiting ...
  32.  
  33.     если у тебя и сейчас проявляется ошибка - маякни - обсудим
  34. */
  35. ***************************
  36. http://joxi.ru/5md7jYwtvD1Vvr
  37.  
  38. /*
  39.     для smart-сущностей - будет отдельный пекедж entities на уровне core
  40.     и там тоже будет деление на element & collection
  41.     в корне entities - будут интерфейсы и общие классы
  42.     а в element & collection - уже элементы и коллекции
  43.  
  44. */
  45. *************************************
  46. public class Text extends ElementCondition {
  47.  
  48.     private String expectedText;
  49.     private String actualText;
  50.     /*
  51.         ты от этого кондишена наследуешься
  52.  
  53.         поменяй у полей объекта - модификаторы доступа - чтоб поля и у потомков были доступны
  54.  
  55.         гугли access modifiers java
  56.     */
  57.  
  58.     public Text(String text) {
  59.         this.expectedText = text;
  60.     }
  61.     /*
  62.         точно такой конструктор - будет нужен и в потомке
  63.         это просто пока запомни
  64.     */
  65.  
  66.     public Text() {
  67.     }
  68.     /*
  69.         а такой конструктор - вообще не нужен
  70.         нам не надо уметь вызывать этот кондиен с пустым параметром
  71.     */
  72.  
  73. ...
  74.     @Override
  75.     public String expected() {
  76.         return expectedText;
  77.     }
  78.  
  79.     @Override
  80.     public String actual() {
  81.         return actualText;
  82.     }
  83.    /*
  84.         точно такие же методы - будут нужны и в потомке
  85.         это просто пока запомни
  86.     */
  87.  
  88. }
  89.  
  90. //смотрим на потомка
  91.  
  92. public class ExactText extends Text {
  93.  
  94.     private String expectedText;
  95.     private String actualText;
  96.     /*
  97.         нам не понадобилось бы объявлять поля - тк поля, объявленные в прдке - были бы доступны
  98.     */
  99.  
  100.     public ExactText(String text) {
  101.         this.expectedText = text;
  102.     }
  103.     /*
  104.         т к нам надо от конструктора ровно то же самое - просто используем super(text);
  105.             http://developer.alexanderklimov.ru/android/java/extends.php
  106.             http://metanit.com/java/tutorial/3.5.php
  107.             https://docs.oracle.com/javase/tutorial/java/IandI/super.html
  108.     */
  109.  
  110.     @Override
  111.     public boolean check(WebElement element) {
  112.         actualText = element.getText();
  113.         return actualText.equals(expectedText);
  114.     }
  115.     /*
  116.         check, конечноб и тут придется реализовать, это верно
  117.  
  118.         а вот на expected() и actual() - ты верно заметил - можно сэкономить
  119.         только и полями объекта надо еще оперировать одними и теми же)
  120.         вот это тоже  - очень важно привести в порядок
  121.     */
  122. }
  123. *******************************
  124. public SmartElement shoudBe(Condition<WebElement> condition) {
  125.         waitFor(this).until(condition);
  126.         return this;
  127. }
  128.  
  129. /*
  130.     не shoud, а should )
  131.  
  132.     и давай реализуем вариант поуниверсальнее - martElement shoudBe(Condition<WebElement>... conditions)
  133.     тут  - просто вызовем public V until(Condition<V>... conditions)
  134.  
  135.     суть такого метода - мы поочередно для переданных кондишенов вызываем until
  136.     как только результат = нуллу = прекратили
  137.  
  138.     в конце - возвращаем результат последней проверки
  139.  
  140.     касается как элементов, так и коллекции
  141. */
  142. **************************
  143. public String toString()
  144. /*
  145.     этот метод есть еще у общего потомка всех классов - Object )
  146.  
  147.     @Override - надо использовать
  148.  
  149.     технически - ты вообще можешь эту аннотацию не использовать
  150.  
  151.         но - согласно конвеншенсов она нужна
  152.         https://google.github.io/styleguide/javaguide.html#s6.1-override-annotation
  153.  
  154.         http://stackoverflow.com/questions/212614/should-we-override-an-interfaces-method-implementation
  155.         http://stackoverflow.com/questions/94361/when-do-you-use-javas-override-annotation-and-why
  156.  
  157.         по второй линке тоже похожие вопросы рассматриваются)
  158.         и народ про них спорит (в варианте - когда мы имплементируем метод интерфейса - там тоже надо аннотировать)
  159.         - есть и pro, и contra )
  160.  
  161.         но вот у гугла в конвеншенсах - указано использовать
  162.  
  163.     и у SmartCollection - аналогичный метод дореализуй
  164. */
  165. ******************дальше учитывай - Lazy = Smart*************************
  166. /*
  167.     у нас - будет несколько классов - лейзи-элементов и лейзи-коллекций
  168.     все лейзи-элементы - должны будут уметь делать - один и тот же перечень действий
  169.     и аналогично - про лейзи-коллекции
  170.  
  171.     логично использовать для лейзи-элементов и лейзи-коллекций
  172.         интерфейс (потомок LazyEntity)
  173.             тут объявляем все методы-действия
  174.         абстрактный класс
  175.             тут реализуем все одинаковое
  176.         потомки -
  177.             тут реализуем только то, что отличает различные классы друг от друга
  178.                 конструктор + необходимые поля
  179.                 toString
  180.                 getWrappedEntity
  181.  
  182.     эти новые интерфейсы логично назвать LazyElement & LazyCollection
  183.     абстрактные классы - AbstractLazyElement & AbstractLazyCollection
  184.     и конечные классы - будут иметь более детальные имена
  185.     (Lazy+откуда+уточнение+Element или Lazy+откуда+уточнение+Collection)
  186.     при таком нейминге - мы учитываем конвеншенсы (про это они тоже есть)
  187.     ниже дам линки
  188.  
  189.     с классами-лейзи-элементами
  190.     как у нас будут обстоять дела
  191.  
  192.     лейзи-элементы любого вида - должны уметь то - что описано в interface LazyElement
  193.     но - получать вебелемент мы будем - по-разному (фактически - реазицация getWrappedEntity)
  194.     например
  195.     мы уже реализовали - getWebDriver().findElement(locator)
  196.     а будет еще и такой вариант  - получить вебэлемент - для такого лейзи-элемента
  197.         lazyElement.find(".destroy")
  198.         lazyCollection.find(cssClass("edited"))
  199.         lazyCollection.get(3)
  200.     т е - в итоге - у нас будет несколько классов, имплементирующих interface LazyElement
  201.     причем - отличаться у них будут лишь конструкторы и  реазицация getWrappedEntity (ну и toString)
  202.     а реализация остальных методов, да и вообще набор методов - один-в-один
  203.  
  204.     вот и получим такую иерархию
  205.  
  206.      самый общий интерфейс
  207.      LazyEntity<T>
  208.  
  209.         его потомки - интерфейсы
  210.             LazyElement
  211.             LazyCollection
  212.  
  213.             абстрактные классы
  214.                 AbstractLazyElement
  215.                 AbstractLazyCollection
  216.                 (реализуем все методы, кроме абстрактного getWrappedEntity,
  217.                  ну и конструктор нам тут не нужен - т к класс абстрактный)
  218.  
  219.                     набор классов - для элементов и коллекций
  220.                         наши уже разработанные варианты
  221.                             LazyWebDriverElement
  222.                             LazyWebDriverCollection
  223.                             (WebDriver = откуда, см схему в нейминге - выше писала)
  224.                         список будет пополняться)
  225.  
  226.      получишь что-то такое http://joxi.ru/GrqLOX3SNZPLoA
  227.      пока закрасила те классы - которые еще у нас не появились)
  228.      ну и разумно - это в рамках core - выделить в отдельный пекедж
  229.      wrappers или entities - хорошее общее название
  230.      т к вот эти наши классы - это лишь обертка вокруг вебэлемента/списка вебэлементов
  231.  
  232.      есть конвеншенсы и по этому поводу - какие имена давать интерфейсу, какие - абстракному предку,
  233.      какие - классам-потомкам
  234.  
  235.      статья про это (лучший вариант)
  236.         http://www.vertigrated.com/blog/2011/02/interface-and-class-naming-anti-patterns-java-naming-convention-tautologies/
  237.      еще полезные линки
  238.          http://stackoverflow.com/questions/2814805/java-interfaces-implementation-naming-convention
  239.          https://web.archive.org/web/20130331071928/http://isagoksu.com/2009/development/java/naming-the-java-implementation-classes
  240.          http://programmers.stackexchange.com/questions/152759/should-i-add-an-abstract-prefix-to-my-abstract-classes
  241.  
  242.      Interfaces, abstract classes - good practice
  243.          http://stackoverflow.com/questions/1932247/abstract-classes-and-interfaces-best-practices-in-java
  244.          http://joxi.ru/E2pdR1lFB1pyM2
  245. */
  246.  
  247. ********************
  248. *
  249.  
  250.     следующий наворот )
  251.  
  252.  
  253.     WebElement - это тоже интерфейс
  254.  
  255.     Если мы отнаследуем наш интерфейс LazyElement от WebElement
  256.     Это то же самое что и заявить - "наш LazyElement - полная замена WebElement - и везде где вы его использовали
  257.    вы теперь можете использовать наш лейзи враппер
  258.    который помимо всех фич вебэлемента еще и будет ждать себя..."
  259.  
  260.     конечно, можно было бы абстрактный класс реализовать имплементирующим два интерфейса
  261.     Класс может быть реализован от нескольких интерфейсов
  262.  
  263.     но тогда, при использовании переменной типа LazyElement - мы не получим функциональности WebElement
  264.  
  265.     потому тут правильнее именно отнаследовать LazyElement от WebElement
  266.  
  267.     Это в java-ООП мире достаточно прикольная практика -
  268.     всегда, когда ты хочешь сделать какие-то штуки внутри объекта публичными -
  269.     выносить их сначала в отдельный интерфейс - и потом его имплементировать
  270.  
  271.     потому что просто сделать какие-то штуки публичными - это недостаточно "строго"
  272.  
  273.     если ты четко заявляешь - мой объект поддерживает такие-то интерфейсы, тогда
  274.     все могут общаться с твоим объектом через четко прописанное API этого интерфейса
  275.  
  276.     тут надо внимательно к вопросу подойти)
  277.  
  278.     в рамках LazyElement - не реализовывай методов, одноименных с методами WebElement
  279.  
  280.     да, мы для некоторых методов потерям chainable возможности
  281.  
  282.     но зато не будет двусмысленностей
  283.  
  284.     в абстрактном классе AbstractLazyElement - реализуй все вебэлементовские методы
  285.     думаю, проблем с этим не будет
  286.  
  287.     думай - в каких методах и чего надо ждать - ничего не ждать / ждать видимости / ждать наличия в DOM
  288.  
  289. */
  290. ***************************************
  291. /*
  292.     следующий наворот )
  293.  
  294.     наворачиваем Collection )
  295.  
  296.         наследуем этот интерфейс и от Iterable<LazyElement>
  297.  
  298.         цель - уметь писать такой код
  299.  
  300.         elements = $$(...);
  301.         for(LazyElement element:elements) {
  302.             ...
  303.         }
  304.  
  305.         т е уметь обходить нашу коллекцию элементов в таком варианте цикла
  306.  
  307.         чистая теория
  308.         http://tutorials.jenkov.com/java-generics/implementing-iterable.html
  309.  
  310.         нам она практически не пригодится )
  311.         просто для понимания - разумно ознакомиться
  312.  
  313.         достаточно понять, что
  314.         при имплементировании интерфейса Iterable<...>
  315.         надо будет реализовать метод
  316.          public Iterator<ProxyElement> iterator()
  317.  
  318.         Дальше мы схитрим)
  319.  
  320.         List<...> тоже наследник Iterable<...>
  321.  
  322.         если мы внутри метода iterator()
  323.             создадим и заполним список list типа List<LazyElement> элементами из коллекции
  324.  
  325.             то тогда можно вернуть в качестве результата метода iterator() - list.iterator();
  326.  
  327.         загвоздка в том, что в коллекции  getWrappedEntity()  возвращает значение типа List<WebElement>
  328.         а мы хотим получить List<LazyElement>
  329.  
  330.         Вот и пришло время создать еще одного потомка для AbstractLazyElement
  331.           назовем его LazyWrappedWebElement (обернутый веб элемент)
  332.           будем передавать ему в конструктор вебЭлемент
  333.           как ты понимаешь, его реазизация getWrappedEntity() - будет возвращать тот же веб элемент
  334.  
  335.         И теперь опять возвращаемся к методу iterator()
  336.         Если в новый список List<LazyElement>
  337.         Ты будешь складывать новосозданные объекты типа LazyWrappedWebElement
  338.         То это будет ОК (т к LazyWrappedWebElement - потомок абстрактного класса который имплементирует интерфейс LazyElement)
  339.  
  340.         Проверяем новую функциональность на коде типа
  341.  
  342.             for (LazyElement element:tasks) {
  343.                 System.out.println(element.getText());
  344.                 element.shouldHave(text("а"));
  345.             }
  346.  
  347. */
  348. **********************************************
  349. /*
  350.       ну и еще один наворот на тему интерфейсов )
  351.  
  352.       как выше писала - класс может имплементировать несколько интерфейсов
  353.  
  354.       и прикольно - всю функциональность описывать на уровне интерфейсов
  355.       это дает ряд интересных полезных эффектов
  356.  
  357.       вот тут например -
  358.       описать интерфейс DescribesResult
  359.       с методами expected() и  actual()
  360.  
  361.       и пусть класс AbstractCondition<V> имплементирует как Condition<V>, так и DescribesResult
  362.  
  363.       первая мелочь - можно описания абстрактных методов отсюда убрать
  364.       (они же и так объявлены в интерфейсе, а реализовывать мы будем в кондишенах уже)
  365.  
  366.       вторая приятная и важная вещь - соблюли лучше Single Responsibility Principle
  367.  
  368.       третья приятная вещь
  369.       конечно, при условии, если таки для переменных-кондишенов будем использовать типы интерфейсов
  370.       Condition<...>
  371.       когда мы будем оперировать переменной
  372.           Condition<...>  condition
  373.  
  374.       то для такой переменной - мы не сможем вызвать методы  expected() /   actual()
  375.       т е - там, где это было нужно - у нас эта функциональность была видна
  376.       а там, где это не нужно - этого вообще не видно
  377.   */
  378. *************************
  379.  
  380. /*
  381.  
  382.   сначала дочитай пассаж, потом решишь - надо ли что-то менять)
  383.     мы немного смухлевали в структуре для кондишенов)
  384.     CollectionCondition & ElementCondition - это как раз абстрактные классы-потомки конечных кондишенов
  385.     но - в именах этих классов - мы не указывали Abstract
  386.  
  387.     Хотя методы, возвращающие кондишены или принимающие кондишены как параметры -
  388.     оперируют интерфейсами - что ок, но не очень просто и лаконично
  389.  
  390.     переделать классы - CollectionCondition & ElementCondition
  391.     в интерфейсы-потомки Condition<List<WebElement>> и Condition<WebElement>
  392.  
  393.     а сами кондишены отнаследовать от абстрактного класса
  394.     (уточняя при этом - <List<WebElement>> или  <WebElement>)
  395.    
  396.     возможно - понадобится имплементировать кондишены от CollectionCondition & ElementCondition
  397.     (проверь, я не уверена в этом)
  398.  
  399.     И тогда методы будут возвращать значение типа интерфейс
  400.         CollectionCondition & ElementCondition
  401.     и в качестве типов параметров у методов should - будут использованы интерфейсы  CollectionCondition & ElementCondition
  402.     что будет чуть красивее
  403.    
  404.     ну и получаем варианты
  405.       0 - остаться при текущей иерархии кондишенов, в принципе все ок и так
  406.      
  407.       1 - улучшить текущую версию и начать использовать интерфейсы CollectionCondition & ElementCondition
  408.       (мы фактически внутрь фреймворка прячем подробности, которые выпирали в варианте 0)
  409.  
  410.       2 - оставить как сейчас +  использовать типы абстрактных классов CollectionCondition & ElementCondition -
  411.       как типы возвращаемых методами значений и типы параметров методов
  412.       Да, тут -  нарушаем конвеншенсы ) Зато в целом код не такой загадочный)
  413.      
  414.       все варианты - с недостатками
  415.       можешь оставить как есть
  416.       можешь - попробовать улучшить
  417. */
Advertisement
Add Comment
Please, Sign In to add comment