julia_v_iluhina

Untitled

Sep 11th, 2016
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 17.67 KB | None | 0 0
  1.    public static String url() {
  2.         String url = getDriver().getCurrentUrl();
  3.         return url;
  4.     }
  5.  
  6. /*
  7.     начнем с мелочей)
  8.  
  9.     тут в одну строку можно
  10.     return getDriver().getCurrentUrl();
  11. */
  12. *******************************************
  13.     public static By byCss(String cssSelector) {
  14.         return cssSelector(cssSelector);
  15.     }
  16. /*
  17.     яркий пример - когда не стоило импорить метод статически
  18.     и использовать вызов без указания класса метода
  19.  
  20.     сравни
  21.     cssSelector(cssSelector)
  22.     и
  23.     By.cssSelector(cssSelector)
  24.  
  25.     все же - второй вариант - однозначнее
  26.  
  27.     тут всегда надо сопоставлять плюсы и минусы
  28.     код должен быть точным и однозначно понимаемым
  29.     тут - By.cssSelector - вариант получше
  30.     вообще - по моему мнению для методов класса By - лучше указывать имя класса
  31. */
  32. ***********************************************
  33.    public static WebElement $(String cssSelector) {
  34.         return $(cssSelector(cssSelector));
  35.    }
  36. /*
  37.     Выше - реализован метод byCss
  38.     стоит его уже тут применять
  39.  
  40.     пока мы делаем только вот эту часть
  41.     http://joxi.ru/Dr860ybhkBb5B2
  42.  
  43.     не торопись все переделать
  44.     мы пока не нуждаемся в функциональности
  45.     $(ExpectedCondition<WebElement> conditionToWaitParentElement, String innerElementCssSelector)
  46.  
  47.     нам достаточно для отладки - наш тест google search
  48.     остальное - можно пока закомментить
  49.     ну и - пока это не нужно - не включать gmail или todoMVC тесты
  50.  
  51.     нам пока и без этого работы хватит
  52.     постепенно с предыдущих заданий - перенесем и  gmail и todoMVC тесты
  53.     сейчас - не надо
  54.     только лишней работы себе добавим
  55. */
  56. ******************************************************
  57. public interface ExpectedCondition<T> {
  58.     T apply(WebDriver driver, By elementsLocator);
  59. }
  60. /*
  61.     согласна, делаем интерфейс для своих кондишенов
  62.     согласна - что apply возвращает значение типа T (какой у нас кондишен - ExpectedCondition<T>)
  63.     согласна - уместно применила T
  64.  
  65.     насчет WebDriver driver
  66.     можем избавиться от него
  67.     мы же реализуем это решение для нашего фреймворка
  68.     и тут - мы можем также - использовать вебдрайвер из ConciseAPI
  69.     и не заводить такого параметра
  70.  
  71.     по By elementsLocator
  72.     да, нам нужен парамент типа By
  73.     но - будет ли это elementsLocator или elementLocator - зависит от обстоятельств
  74.     потому - корректнее использовать более нейтральный термин - locator
  75.  
  76.     по имени интерфейса
  77.     лучше не использовать классов с таким же именем, что и у стандартных классов
  78.     предлагаю тут вариант Condition<T>
  79. */
  80. *******************************************
  81.    protected static <V> V waitUntil(ExpectedCondition<V> condition, By elementsLocator, long timeOutInSeconds) {
  82.    /*
  83.         тут тоже - про имя  elementsLocator
  84.         корректнее - locator
  85.    */
  86.         final long startTime = System.currentTimeMillis();
  87.         do {
  88.             V v = condition.apply(getDriver(), elementsLocator);
  89.             if (v != null) {
  90.                 if (v.getClass().isAssignableFrom(Boolean.class) && v == Boolean.TRUE ||
  91.                         !v.getClass().isAssignableFrom(Boolean.class)) {
  92.                 /*
  93.                     на самом деле, толку от реализации кондишенов как Condition<Boolean> - мало
  94.                     что нам даст возвращенный true?
  95.                     да ничего нового
  96.                     раз проверка не упала - значит и так понятно - что проверка прошла
  97.  
  98.                     мы  - сами себе хозяева
  99.                     и можем для себя решить - что не будем делать Condition<Boolean>
  100.  
  101.                     нам будет достаточно
  102.                     Condition<WebElement>
  103.                     и
  104.                     Condition<List<WebElement>>
  105.  
  106.                     а раз так - значит вот этого if (v.getClass().isAssignableFrom....
  107.                     не надо)
  108.                 */
  109.                     return v;
  110.                 }
  111.             }
  112.             sleep(collectionsPollingInterval);
  113.             /*
  114.                 вот тут - лучше подробнее
  115.                 Configuration.pollingInterval
  116.  
  117.                 и про collections - тут не надо писать)
  118.                 т к опять же - мы точно не знаем
  119.                 для коллекции элементов или для элемента мы будем делать проверку
  120.             */
  121.         }
  122.         while (System.currentTimeMillis() - startTime < timeOutInSeconds * 1000);
  123.         return condition.apply(getDriver(), elementsLocator);
  124.         /*
  125.             а вот тут нам надо - раз нам не хватило таймаута для проверки
  126.             бросить исключение
  127.             у Selenium - есть TimeoutException
  128.             вот его и вызови тут
  129.             new TimeoutException(...);
  130.         */
  131.     }
  132. /*
  133.     в целом - молодец, переварила )
  134.  
  135.     чуть наворачиваем)
  136. */
  137.  
  138. /*
  139.     хорошая идея - реализовать умное ожидание в отдельном классе
  140.     с точки зрения Single Responsibility - так будет лучше
  141.  
  142.     наглядно этот класс назвать WaitFor
  143.     а статический метод-умный ожидатель выполнения кондишена - until
  144.     и в коде мы будем писать WaitFor(byCss(...)).until(visible())
  145.     получится очень наглядная и понятная фраза
  146.  
  147.     в том же классе - расположи и метод sleep
  148.     а его сделай - private
  149.     т к sleep будет нужен только для реализации ждущей проверки
  150. */
  151. *********************************************************
  152.  
  153.    public static ExpectedCondition<List<WebElement>> texts(final String... expectedTexts) {
  154.         return elementExceptionsCatcher(new ExpectedCondition<List<WebElement>>() {
  155.      ....
  156.         });
  157.     }
  158. /*
  159.     Теперь - давай реализовывать кондишены не как анонимные классы, а как отдельные классы
  160.  
  161.     а в CustomConditions - будут статические лаконичные методы
  162.  
  163.     типа
  164.  
  165. */
  166.  
  167.     public static Condition<List<WebElement>> texts(final String... texts) {
  168.         return new Texts(texts);
  169.     }
  170. /*
  171.     в реализации самого кондишена - elementExceptionsCatcher использовать не будем
  172.  
  173.     это мы сделаем внутри цикла в ждущей проверке - будем ловить те же исключения
  174.  
  175.     такой способ реализации кондишенов - даст нам несколько бонусов приятных
  176.     чуть позже разберем)
  177.  
  178.     чтоб не загромождать пекедж core
  179.      создай в нем пекедж conditions
  180.      и там расположи все, что касается кондишенов
  181. */
  182. ***************************************************
  183.     public static ExpectedCondition<WebElement> visibilityOfElement() {
  184. /*
  185.     смотри имя - мы проверяем видимость элемента (одного)
  186. */
  187. ...
  188.                 elements = driver.findElements(elementsLocator);
  189.                 /*
  190.                     потому и тут - можем просто получить элемент
  191.                     driver.findElement(...)
  192.                 */            
  193. ****************************************************
  194.  
  195. /*
  196.     Иерархия для кондишенов у тебя сейчас - достаточно простая
  197.  
  198.     интерфейс
  199.     и классы-кондишены, имплементирующие его
  200.  
  201.     Минимально необходимая реализация есть
  202.  
  203.     Будем ее развивать
  204.  
  205.     Далее - реализуй абстрактный класс-предок AbstractCondition<V> ,
  206.     который имплементирует интерфейс Condition<V>
  207.    
  208.     Статья про нейминг
  209.     http://www.vertigrated.com/blog/2011/02/interface-and-class-naming-anti-patterns-java-naming-convention-tautologies/
  210.  
  211.     Теперь смотрим дальше
  212.     Нам хочется, чтобы наш toString() для любого кондишена был хорошо структурирован
  213.     Это значит, чтобы фразы были типа
  214.  
  215.           имя кондишена +
  216.           for ____element/elements___ found by: ___locator___
  217.           expected ___expected result desription_____
  218.           actual ____actual result description
  219.  
  220.     Можно конечно в каждом из кондишенов просто строить такую фразу
  221.     согласно правилу
  222.     А можно - toString() реализовать в абстрактном классе, и внутри этого метода - вызывать абстрактные методы
  223.     а их уже - реализуем в потомках. Таким образом - структура сообщения любого из кондишенов
  224.     будет одинаковой
  225.  
  226.     Имя кондишена
  227.     раз мы будем реализовывать кондишены как отдельные классы - потомки (пока - нашего абстрактного класса)
  228.     то откуда взять имя кондишена - у нас есть
  229.     у нас есть имя класса кондишена - чем не имя )
  230.  
  231.     Далее
  232.     element/elements
  233.     Это только верхушечка айсберга
  234.     Да, схема проверки кондишенов - у нас одна и та же
  235.     Хоть это кондишен для списка элементов
  236.     Хоть для элемента
  237.     И нам нужно, чтоб наш waitUntil был один и работал с любым кондишеном
  238.  
  239.     Но
  240.     Нам важна разница - что это за кондишен - для элемента или коллекции
  241.     В данный момент - чтобы сказать про то в фразе - for ____element/elements
  242.     А далее (в следующих заданиях) - чтобы кондишены для element - мы просто  НЕ МОГЛИ применить к elements
  243.     Таким образом, приходим к тому, что у нашего общего предка AbstractCondition<V>
  244.     Будут 2 абстрактных потомка
  245.         CollectionCondition extends AbstractCondition<List<WebElement>>
  246.         ElementCondition extends AbstractCondition<WebElement>
  247.     От которых мы будем наследовать наши реальные кондишены
  248.  
  249.     И тогда, стоит держать 2 класса для реализации статических методов - вызовов кондишенов
  250.     не один, как сейчас у тебя - Conditions
  251.     а 2 =  CollectionConditions и  ElementConditions
  252.     чтобы каталоги проверок были разными для этих 2-ух типов проверок
  253.  
  254.     С иерархией разобрались немного )
  255.     Возвращаемся к фразе в toString()
  256.     Если этот метод реализовать в главном предке AbstractCondition,
  257.     и этот метод будет использовать абстрактные методы, возвращающие строки
  258.     для всех элементов этой фразы
  259.     То структура сообщения о кондишене - будет всегда четкой
  260.  
  261.     А нам останется - реализовать эти абстрактные методы, возвращающие строки
  262.     в потомках
  263.     Тут будь внимательной
  264.     Некоторые из методов надо будет реализовать уже в кондишенах-потомках
  265.     Некоторые - в CollectionCondition и ElementCondition
  266.  
  267.     Руководствуйся такими рассуждениями
  268.     Если во всех потомках я пишу одинаковый код
  269.     То лучше этот код написать в предке
  270.  
  271.     Что касается типа параметра condition для
  272.     until(Condition<V> condition)
  273.  
  274.     Ты можешь указать интерфейс Condition<V>
  275.  
  276.     И метод будет корректно работать для любого из кондишенов
  277.     Т к этот интерфейс лежит в основе этой иерархии
  278. */
  279. ***************************************************
  280. /*
  281.     еще один наворот внутри кондишенов)
  282.  
  283.     мы его впоследствии переделаем
  284.  
  285.     сейчас нам это нужно для лучшего понимания процесса
  286.  
  287.     в apply передают локатор
  288.     описание которого мы возвращаем в одном из методов кондишена (для ToString)
  289.     и это - справедливо для всех кондишенов
  290.  
  291.     потому в AbstractCondition заводим переменную locator
  292.     в которую сохраняем переданный в apply локатор
  293.  
  294.     и уже в методе, возвращающем описание локатора,
  295.     оперируем этой переменной
  296.  
  297.     сразу подумай, какой модификатор доступа использовать для такой переменной
  298.     http://www.quizful.net/interview/java/access-modifiers
  299.  
  300.     но это опять была только верхушка айсберга)
  301.  
  302.     посмотри на реализованные кондишены
  303.     первой строкой в методе проверок - у тебя идет
  304.     List<WebElement> elements = getDriver().findElements(elementsLocator);
  305.     или
  306.     WebElement element = getDriver().findElement(elementsLocator);
  307.     (таких, кстати, пока нету
  308.         реализуй
  309.         visible
  310.         present
  311.         text
  312.         exactText
  313.     )
  314.  
  315.     Так вот
  316.     фактически - вот это
  317.     List<WebElement> elements = getDriver().findElements(elementsLocator);
  318.     или
  319.     WebElement element = getDriver().findElement(elementsLocator);
  320.  
  321.     это сущность типа V с точки зрения класса AbstractCondition
  322.  
  323.     давай метод check изменим
  324.     пусть принимает не локатор
  325.     а уже V entity (т е внутри кондишена в реализации check
  326.     нам ничего не придется искать по локатору - нам это уже на вход передадут)
  327.  
  328.     а вот в реализации apply в AbstractCondition
  329.     для получения этого V entity
  330.     мы объявим новый абстрактный метод getWrappedEntity()
  331.     который будет нам возвращать значение типа V
  332.  
  333.     а реализуем его в классах CollectionCondition и ElementCondition
  334.  
  335.     думаю, ты догадаешься, как )
  336.  
  337.     а вот потом, когда у нас будут наши классы для элементов (следующее задание)
  338.     мы будем в apply передавать не локатор
  339.     а сам элемент нашего нового класса
  340.     и сам элемент будет возвращать getWrappedEntity()
  341.     и мы тут, в кондишенах, избавимся от  getWrappedEntity() и его реализаций )
  342.  
  343.     пока это такой костыль
  344.     нарушающий принцип Single Responsibility
  345.     но позволяющий нам сейчас максимально реализовать код
  346.     который впоследствии изменим минимально
  347. */
Advertisement
Add Comment
Please, Sign In to add comment