julia_v_iluhina

Untitled

Sep 24th, 2016
76
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 13.26 KB | None | 0 0
  1.  public static <V> V waitUntil(By locator, Condition<V> condition, long timeoutMs)  {
  2.  /*
  3.     молодец - что все таймауты в миллисекундах
  4.     уже и название параметров для таймаута поправь
  5.  
  6.     только тут timeoutMs
  7.     в остальных местах - используешь timeout
  8.     при этом  - везде четко используешь значение в миллисекундах
  9.  
  10.     советую поправить тут - на timeout
  11.     а в Configuration - написать комментарии
  12.  */
  13.        ...
  14.             } catch (StaleElementReferenceException | ElementNotVisibleException
  15.                     | IndexOutOfBoundsException | NoSuchElementException e) {
  16. /*
  17.     посмотри на предков всех перечисленных исключений (зажать ctrl плюс кликнуть на имени класса,
  18.     возможно - так несколько раз)
  19.     у всех, кроме  IndexOutOfBoundsException - предком является WebDriverException
  20.  
  21.     можешь ловить лишь IndexOutOfBoundsException и WebDriverException - будет не хуже )
  22. */
  23. ...
  24.  
  25.         throw new TimeoutException(String.format("Locator ['%s'], timeout ['%s'] sec, Condition ['%s'] " +
  26.                 " Error is ['%s']",locator.toString(), timeoutMs/1000, condition.toString(), lastError), lastError);
  27. /*
  28.         failed while waiting ... seconds
  29.         to assert __condition___
  30.  
  31.          __condition___ - это как раз toString кондишена
  32.          остальное полезное и умное - напишем там
  33. */
  34. *****************************************************
  35.  
  36. /*
  37.     хорошая идея - реализовать умное ожидание в отдельном классе
  38.     с точки зрения Single Responsibility - так будет лучше
  39.  
  40.     наглядно этот класс назвать WaitFor
  41.     а статический метод-умный ожидатель выполнения кондишена - until
  42.     и в коде мы будем писать waitFor(byCss(...)).until(visible())
  43.     получится очень наглядная и понятная фраза
  44.  
  45.     в том же классе - расположи и метод sleep
  46.     а его сделай - private
  47.     т к sleep будет нужен только для реализации ждущей проверки
  48.  
  49.     чтобы так писать - waitFor(byCss(...)).until(visible())
  50.         реализуй конструктор с параметром By locator
  51.  
  52.         реализуй статический метод waitFor с параметром By locator
  53.         возвращающий - новый объект класса WaitFor
  54.  
  55.         реализуй метод until(...)
  56.     получишь
  57.        waitFor(byCss(...)). - создали объект типа WaitFor
  58.           until(visible()) - вызвали у него метод until
  59.  
  60.     конечно, until-у передаай как кондишен, так и таймаут
  61.     уже второй вариант  until-а - без таймаута (также как и раньше - такой берет таймаут по умолчанию
  62. */
  63. *********************************************
  64. /*
  65.     Иерархия для кондишенов у тебя сейчас - достаточно простая
  66.  
  67.     интерфейс
  68.     и классы-кондишены, имплементирующие его
  69.  
  70.     Минимально необходимая реализация есть
  71.  
  72.     Будем ее развивать
  73.  
  74.     Далее - реализуй абстрактный класс-предок AbstractCondition<V> ,
  75.     который имплементирует интерфейс Condition<V>
  76.  
  77.     Статья про нейминг
  78.     http://www.vertigrated.com/blog/2011/02/interface-and-class-naming-anti-patterns-java-naming-convention-tautologies/
  79.  
  80.     Теперь смотрим дальше
  81.     Нам хочется, чтобы наш toString() для любого кондишена был хорошо структурирован
  82.     Это значит, чтобы фразы были типа
  83.  
  84.           __имя кондишена__ +
  85.           for ____element/elements___ found by: ___locator___
  86.           expected ___expected result description_____
  87.           actual ____actual result description_____
  88.  
  89.     Можно конечно в каждом из кондишенов просто строить такую фразу
  90.     согласно правилу
  91.  
  92.     А можно - toString() реализовать в абстрактном классе, и внутри этого метода - вызывать абстрактные методы
  93.     а их уже - реализуем в потомках. Таким образом - структура сообщения любого из кондишенов
  94.     будет одинаковой
  95.  
  96.     где брать ___locator___ тут - мы чуть позже поговорим...
  97.     пока пропусти этот момент
  98.  
  99.     а вто для
  100.         ____element/elements___
  101.         ___expected result description_____
  102.         ____actual result description____
  103.     объяви и используй абстрактные методы
  104.         identity()
  105.         expected()
  106.         actual()
  107.  
  108.     __имя кондишена__
  109.     раз мы будем реализовывать кондишены как отдельные классы - потомки (пока - нашего абстрактного класса)
  110.     то откуда взять имя кондишена - у нас есть
  111.     у нас есть имя класса кондишена - чем не имя )
  112.  
  113.     Далее
  114.     element/elements
  115.     Это только верхушечка айсберга
  116.     Да, схема проверки кондишенов - у нас одна и та же
  117.     Хоть это кондишен для списка элементов
  118.     Хоть для элемента
  119.     И нам нужно, чтоб наш waitUntil был один и работал с любым кондишеном
  120.  
  121.     Но
  122.     Нам важна разница - что это за кондишен - для элемента или коллекции
  123.     В данный момент - чтобы сказать про то в фразе - for ____element/elements
  124.     А далее (в следующих заданиях) - чтобы кондишены для element - мы просто  НЕ МОГЛИ применить к elements
  125.     Таким образом, приходим к тому, что у нашего общего предка AbstractCondition<V>
  126.     Будут 2 абстрактных потомка
  127.         CollectionCondition extends AbstractCondition<List<WebElement>>
  128.         ElementCondition extends AbstractCondition<WebElement>
  129.     От которых мы будем наследовать наши реальные кондишены
  130.  
  131.     И тогда, стоит держать 2 класса для реализации статических методов - вызовов кондишенов
  132.     CollectionConditions и  ElementConditions
  133.         это будут классы-контейнеры статических методов
  134.         типа
  135.         public static Condition<WebElement> visible() {
  136.             return new Visible();
  137.         }
  138.         чтобы уже в коде  - не писать - new Visible()
  139.  
  140.     С иерархией разобрались немного )
  141.  
  142.     Возвращаемся к фразе в toString()
  143.         Если этот метод реализовать в главном предке AbstractCondition,
  144.         и этот метод будет использовать абстрактные методы, возвращающие строки
  145.         для всех элементов этой фразы
  146.         То структура сообщения о кондишене - будет всегда четкой
  147.  
  148.     А нам останется - реализовать эти абстрактные методы, возвращающие строки
  149.     в потомках
  150.     Тут смотри внимательно
  151.     Некоторые из методов надо будет реализовать уже в кондишенах-потомках
  152.     Некоторые - в CollectionCondition и ElementCondition
  153.  
  154.     Руководствуйся такими рассуждениями
  155.     Если во всех потомках я пишу одинаковый код
  156.     То лучше этот код написать в предке
  157.  
  158.     Что касается типа параметра condition для
  159.     until(Condition<V> condition)
  160.  
  161.     Ты можешь указать интерфейс Condition<V>
  162.  
  163.     И метод будет корректно работать для любого из кондишенов
  164.     Т к этот интерфейс лежит в основе этой иерархии
  165. */
  166. ***************************************************
  167. /*
  168.     еще один наворот внутри кондишенов)
  169.  
  170.     мы его впоследствии переделаем
  171.  
  172.     сейчас нам это нужно для лучшего понимания процесса
  173.  
  174.     в apply передают локатор
  175.     описание которого мы возвращаем в одном из методов кондишена (для ToString)
  176.     и это - справедливо для всех кондишенов
  177.  
  178.     и нам - еще в AbstractCondition интересно сохранить этот локатор
  179.  
  180.     потому в AbstractCondition заводим переменную locator
  181.     и реализуем метод apply
  182.     в котором
  183.         сохраняем переданный в apply локатор
  184.         и вызываем абстрактный метод check
  185.         (- который, собственно, и нужно будет в кондишенах реализовывать вместо apply)
  186.  
  187.     check - будет делать то же, что и  apply делал ранее
  188.     нам  это нужно было для того, чтоб локатор получить еще на уровне абстрактного класса
  189.  
  190.     теперь - и в toString - мы можем подправить фразу - про локатор
  191.  
  192.     сразу подумай, какой модификатор доступа использовать для такой переменной
  193.     http://www.quizful.net/interview/java/access-modifiers
  194.  
  195.     но это опять была только верхушка айсберга)
  196.  
  197.     посмотри на реализованные кондишены
  198.     первой строкой в методе проверок - у тебя идет
  199.     List<WebElement> elements = getDriver().findElements(elementsLocator);
  200.     или
  201.     WebElement element = getDriver().findElement(elementsLocator);
  202.     (таких, кстати, пока нету
  203.         реализуй
  204.         visible
  205.         present
  206.         text
  207.         exactText
  208.     )
  209.  
  210.     Так вот
  211.     фактически - вот это
  212.     List<WebElement> elements = getDriver().findElements(elementsLocator);
  213.     или
  214.     WebElement element = getDriver().findElement(elementsLocator);
  215.  
  216.     это сущность типа V с точки зрения класса AbstractCondition
  217.  
  218.     давай метод check изменим
  219.     пусть принимает не локатор
  220.     а уже V entity (т е внутри кондишена в реализации check
  221.     нам ничего не придется искать по локатору - нам это уже на вход передадут)
  222.  
  223.     а вот в реализации apply в AbstractCondition
  224.     для получения этого V entity
  225.     мы объявим новый абстрактный метод getWrappedEntity()
  226.     который будет нам возвращать значение типа V
  227.  
  228.     а реализуем его в классах CollectionCondition и ElementCondition
  229.  
  230.     думаю, ты догадаешься, как )
  231.  
  232.     а вот потом, когда у нас будут наши классы для элементов (следующее задание)
  233.     мы будем в apply передавать не локатор
  234.     а сам элемент нашего нового класса
  235.     и сам элемент будет возвращать getWrappedEntity()
  236.     и мы тут, в кондишенах, избавимся от  getWrappedEntity() и его реализаций )
  237.  
  238.     пока это такой костыль
  239.     нарушающий принцип Single Responsibility
  240.     но позволяющий нам сейчас максимально реализовать код
  241.     который впоследствии изменим минимально
  242. */
Advertisement
Add Comment
Please, Sign In to add comment