julia_v_iluhina

Untitled

Nov 28th, 2016
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 19.00 KB | None | 0 0
  1. actualState = (element != null ? true : false);
  2. //или
  3. actualState = (element != null);
  4. /*
  5.     это - одно и то же технически
  6.  
  7.     рекомендую второй вариант)
  8. */
  9. ****************************
  10. new Actions(getDriver())
  11. /*
  12.     вот этот код - можно завернуть в метод actions() - в ConciseAPI
  13. */
  14. ******************************
  15.     @Override
  16.     public LazyElement setValue(CharSequence... charSequences) {
  17.         System.out.println(this.toString());
  18.         clear();
  19.         sendKeys(charSequences);
  20.         return this;
  21.     }
  22. /*
  23.     отладочное сообщение - убирай
  24.  
  25.     и в clear(), и в sendKeys - уже встроены ожидания
  26.     получается - тут мы дважды ждем
  27.  
  28.     чуть оптимальнее было бы - подождать видимости  - один раз
  29.     а затем для вебэлемента вызвать и clear(), и  sendKeys(..)
  30.  
  31.     так будет менее DRY,  конечно
  32.     нас оправдывает именно то, что мы оптимизируем действия
  33. */
  34. *****************************************
  35.         if (apply != null) {
  36.             return true;
  37.         }
  38. /*
  39.     можно проще в is(..) поступить
  40.  
  41.     return (apply != null);
  42. */
  43. *****************************************
  44. public class LazyElementInnerElement extends AbstractLazyElement {
  45. ...
  46.     private LazyEntity<WebElement> parentElement;
  47. /*
  48.     почему не LazyElement?
  49.     достаточно уточниться до интерфейса, который имплементируется родительским объектом
  50.     глубже по иерархии не нужно идти
  51.  
  52.     это же касается и родительских сущностей в других классах
  53.     LazyCollectionNthElement, например
  54.  
  55.     если мы точно знаем - что есть родительская лейзи-сущность - элемент или коллекция
  56.     так отлично - используй интерфейсы LazyElement или LazyCollection
  57.  
  58.     а вот если не знаем - что есть родительская лейзи-сущность - то уже применяем LazyEntity(и не уточняем generic тип)
  59. */
  60. ....
  61.     @Override
  62.     public String toString() {
  63.         return "LazyElementInnerElement{" +
  64.                 "locator=" + locator +
  65.                 " from " + parentElement +
  66.                 '}';
  67.     }
  68.  
  69.     /*
  70.         советую применять в toString() - простые лаконичные и точные формулировки
  71.         и избегать применять наши термины - имена классов
  72.         просто опиши  - как мы получили этот элемент
  73.         этого достаточно
  74.  
  75.         return parentElement + " find(" + innerLocator + ")";
  76.  
  77.         упрости и в других лейзи-сущностях выражения в toString()
  78.         там, где отталкиваемся только от локатора - достаточно просто локатора
  79.     */
  80. ***********************************************
  81. public class LazyWrappedWebElement extends AbstractLazyElement {
  82.  
  83.   ....
  84.     @Override
  85.     public String toString() {
  86.         return "LazyWrappedWebElement element = " + element +  " from "+ parentEntity + "}";
  87.     }
  88. /*
  89.     return "WebElement " + element + " from " + parentEntity; ?
  90. */
  91. *************************************************
  92. public class LazyCollectionFilterCollection extends AbstractLazyCollection{
  93. /*
  94.     лучше не Filter, а Filtered
  95.  
  96.     в данном случае - можно подсократить до LazyFilteredCollection
  97.     причины - и так ясно - что за источник
  98.     раз получили на выходе - коллекцию, отфильтровав что-то
  99.     но это что-то - тоже коллекция
  100.  
  101.     не настаиваю на сокращении
  102.  
  103. */
  104.  ...
  105.  
  106.     @Override
  107.     public List<WebElement> getWrappedEntity() {
  108. /*
  109.     почти идеальная реализация
  110.  
  111.     почти - потому что в List<WebElement> filteredElements
  112.     правильнее добавлять не LazyWrappedWebElement, а сам webElement
  113.  
  114.     еще можно было бы сэкономить на создании LazyWrappedWebElement
  115.     если бы метод check кондишена біл нам доступен
  116.     он уже принимает WebElement и возвращает нам нужній да/нет
  117.  
  118.     можешь для начала просто вынести метод check на уровень интерфейса Condition
  119.     потом это лучше структурируем
  120. */
  121.     @Override
  122.     public String toString() {
  123.         return "LazyCollectionFilterCollection{" +
  124.                 "parentCollection = " + parentCollection.getClass().getSimpleName() +
  125.                 ", condition = " + condition +
  126.                 '}';
  127.     }
  128. /*
  129.     Для кондишена - применяй тоже getClass().getSimpleName()
  130.     нам достаточно этих подробностей этих (вспомни, как toSrting кондишена формируется - так нам точно не надо)
  131.  
  132.     return parentCollection.toString() + " filter(" + condition.getClass().getSimpleName() + ")"; - будет ок
  133.  
  134.     не настаиваю именно на моих вариантах
  135.     смысл - чтоб даже тот, кто не полез разбираться в наш фреймворк
  136.     понимал тексты  об ошибках
  137.     и по описанию элемента - узнавал свой код
  138.  
  139. */
  140. ***************************************
  141. public class LazyCollectionFindElement extends AbstractLazyElement {
  142. /*
  143.     LazyCollectionFoundElement
  144.     LazyCollectionFoundByConditionElement - мне вот такой вариант больше нравится
  145.  
  146. */
  147.  
  148.     @Override
  149.     public WebElement getWrappedEntity() {
  150. /*
  151.     тут - та же история, как и для LazyCollectionFilterCollection
  152. */
  153.     @Override
  154.     public String toString() {
  155. /*
  156.     Тут - похоже тоже на вариант для LazyCollectionFilterCollection
  157. */
  158. *****************************************
  159. public interface Condition<T> {
  160.     T apply(LazyEntity<T> entity);
  161.  
  162.     boolean check(T wrappedEntity);
  163. }
  164.  
  165. /*
  166.     делаем красиво)
  167.  
  168.     сейчас в этом интерфейсе - объявлены методы
  169.         служащие как для принятия решения - прошли-не прошли
  170.         так и для получения результата ожидания
  171.  
  172.     нарушаем Single Responsibility Principle )
  173.  
  174.     реализуй интерфейс Matcher <T> с объявленным методом boolean check(T wrappedEntity);
  175.  
  176.     а в Condition <T> - останется apply
  177.     Condition <T> - отнаследуй от Matcher <T>
  178.  
  179.     используй check и для метода is
  180. */
  181. **************************************
  182.   public void delete(String taskText) {
  183.         tasks.find(text(taskText)).hover();
  184.         $(".destroy").click();
  185.    }
  186. /*
  187.     вот это слишком большое упрощение -  $(".destroy")
  188.     нам откуда нужна эта кнопка
  189.     четко из таски, на которой делали hover()
  190.  
  191.     потому - оттолкнись от правильного элемента
  192.     и внутри него ищи кнопку
  193.  
  194.     это и других методов этого пейджа касается
  195.     тут тебе поможет код, который использовала в Selenide
  196. */
  197. *************************************************
  198. реализовала новые методы. Тесты падают на doubleClick и hover.
  199. /*
  200.   суть в чем
  201.     например, при первом получении getWrappedEntity для
  202.         tasks.find(cssClass("editing")).find(".edit")
  203.  
  204.     в getWrappedEntity для LazyElementInnerElement
  205.     мы выполняем
  206.     parentElement.getWrappedEntity().findElement(innerLocator)
  207.  
  208.     а в этот момент
  209.     parentElement.getWrappedEntity() = null
  210.  
  211.     и мы получается у null пытаемся получить findElement(innerLocator)
  212.  
  213.     и тут происходит ошибка, которую мы не ловим
  214.     и которую ловить - нельзя (технически - можно, но - не правильно)
  215.  
  216.     вот линка, почитай, достаточно внятная
  217.     http://howtodoinjava.com/core-java/exception-handling/how-to-effectively-handle-nullpointerexception-in-java/
  218.  
  219.     а потом углуби понимание http://www.yegor256.com/2014/05/13/why-null-is-bad.html
  220.     особенно внимательно на вот этот кусок посмотри http://joxi.ru/5md7jYwtvV5k8r
  221.  
  222.     получается - что good practice = обходить эти проблемы
  223.     а не перехватывать NullPointerException
  224.  
  225.     можно конечно поступить так (это первое, что приходит в голову, НО МЫ ТАК ДЕЛАТЬ НЕ БУДЕМ)
  226.  
  227.         переписывать getWrappedEntity()
  228.             вместо
  229.             return parentElement.getWrappedEntity().findElement(innerLocator);
  230.             пишем
  231.             return parentElement.getWrappedEntity() == null ? null : parentElement.getWrappedEntity().findElement(innerLocator);
  232.  
  233.         аналогично - и в других классах
  234.  
  235.         кроме этого - поправить apply кондишена - чтобы check вызывался только если его аргумент не равен нуллу
  236.  
  237.     как ты понимаешь - это куча изменений, и достаточно легко что-то пропустить
  238.     лучше - опереться на одно правило и его придерживаться в коде
  239.  
  240.     правило - наш код не возвращает null,
  241.     вместо этого - вызываем исключение (напоминаю про http://joxi.ru/5md7jYwtvV5k8r)
  242.  
  243.     Дорабатываем наши кондишены
  244.         метод check - у нас уже возвращает значение типа boolean (прошла/не прошла проверка)
  245.         в apply -
  246.             если проверка не прошла - вместо того, чтобы возвращать null -
  247.             вызываем исключение WebDriverAssertionException (отнаследуй от WebDriverException)
  248.  
  249.             тут, в apply не применяем try-catch
  250.  
  251.     В WaitFor
  252.         дорабатываем метод until
  253.             как раз тут у нас уже есть try-catch
  254.  
  255.             получается, что если apply бросит ошибку
  256.             то мы попадем в секцию catch ( в которой эту ошибку просто запомним - в переменную)
  257.             (WebDriverException - мы тут ловим, значит - поймаем и WebDriverAssertionException)
  258.  
  259.             а если apply не бросит ошибку - значит все ок - проверка прошла
  260.             потому и делаем сразу return condition.apply(lazyEntity)
  261.  
  262.             итого получили
  263.               в реализация кондишена - мы нуллы нигде не возвращаем (или хорошее значение, или исключение)
  264.               в реализации вейт антила - тоже самое
  265.               причем исключения - используем разные (каждая ситуация = свое исключение)
  266.  
  267.            следующий момент
  268.              еще один источник null - результат getWrappedEntity() для потомков AbstractLazyElement
  269.              для коллекций такого не будет - с будет просто пустой список
  270.              а вот с элементами - да, будет
  271.              потому - надо чуть доработать код в getWrappedEntity() для классов семейства LazyElement
  272.  
  273.              применяем ту же логику - мы нуллы нигде не возвращаем (или хорошее значение, или исключение)
  274.                 в AbstractLazyElement реализуем getWrappedEntity()
  275.                 который вызывает абстрактный метод fetchWrappedEntity() (новый, возвращающий WebElement)
  276.                 и если результат fetchWrappedEntity() равен нулл
  277.                 то getWrappedEntity() вызовет исключение
  278.                 ElementNotFoundException (также отнаследуем от WebDriverException,
  279.                 раз у нас уже несколько своих исключений - в core создай для них свой пекедж exceptions)
  280.  
  281.                 а реализация fetchWrappedEntity() - это то, что мы ранее реализовывали в getWrappedEntity()
  282.  
  283.                 и тут тоже, смотри внимательно
  284.                 если мы сами пишем код (а не вызываем что-то стороннее)
  285.                 то тоже также - мы нуллы нигде не возвращаем (или хорошее значение, или исключение)
  286.  
  287.              получили и для getWrappedEntity() - нулла нам теперь этот метод не возвращает
  288.              а это значит - не надо думать про вызовы getWrappedEntity().... - как
  289.              про источник NullPointerExteption
  290.  
  291.           еще небольшой наворот, раз уж мы так развили работу с исключениями
  292.             в getWrappedEntity() класса LazyCollectionNthElement
  293.             перехватим с помощью try-catch исключение IndexOutOfBoundsException
  294.             и вместо него бросим свое исключение
  295.             LazyСollectionIndexOutOfBoundsException (также отнаследуем от WebDriverException)
  296.  
  297.             что это нам даст
  298.             в WaitFor.until
  299.             можно ловить только WebDriverException
  300.  
  301.             т е  - получили более стройную логику
  302.  
  303.           а за счет того, что помимо ранее выводимой детальной информации
  304.           о проверке, мы еще и выводим информацию об ошибке, которая привела к тому,
  305.           что ошибка не прошла - информация о проблеме - максимально полная
  306.  
  307.           да и то, что мы нигде сами не возвращаем нуллы
  308.           сделало наш код надежнее и проще
  309.  
  310.           теперь - тесты todoMVC падать не должны)
  311. */
  312. **********************************************
  313. /*
  314.     еще немного challenge )
  315.  
  316.     в интерфейсе LazyElement
  317.         объяви методы
  318.     LazyCollection findAll(By innerLocator);
  319.     LazyCollection findAll(String innerCssSelector);
  320.  
  321.     и реализуй их в AbstractLazyElement
  322.  
  323.     этот метод позволит у элемента  - по селектору или локатору - получить коллекцию внутренних элементов
  324.  
  325.     отладиться можно - используя
  326.     LazyCollection tasks = $("#todo-list").findAll("li");
  327.     или
  328.     LazyCollectionLazyCollection emails = $("[role='main']").findAll(".zA");
  329.  
  330.     Иногда такой метод findAll будет очень полезным
  331.  
  332.     принципы - те же
  333.     как ты до этого реализовывала методы get, find, filter ...
  334.  
  335.     так сказать - для закрепления результатов)
  336. */
  337. **************************************
  338. /*
  339.     насчет использования модификатора доступа protected
  340.  
  341.         есть такая точка зрения, что использовать protected - это самообман
  342.         т к в рамках потомков можно для отнаследованного protected-метода
  343.         этот метод сделать публичным
  344.  
  345.         когда мы использовали protected, мы хотели, чтобы что-то было с возможностью наследования
  346.         и не хотели его внешнего использования.
  347.         а кто-то отнаследовался от нашего класса и объявил это как public
  348.         и вот то, что мы прятали внутри класса - уже "торчит" наружу
  349.  
  350.         есть good practice - избегать применения protected
  351.         то, что мы что-то объявим внутри класса-кондишена как public
  352.         не будет нам особо мешать при работе с нашим фреймворком
  353.         т к в итоге - используем для кондишена тип интерфейс,
  354.         и это позволит не светить нашими публичными переменными/методами
  355.         когда будем юзать фреймворк
  356.  
  357.         идеально про протектед-методы
  358.             http://programmers.stackexchange.com/questions/162643/why-is-clean-code-suggesting-avoiding-protected-variables
  359.             http://joxi.ru/52akqzoUGnqYGr
  360.  
  361.             http://stackoverflow.com/questions/3631176/why-are-many-developers-opposed-to-using-the-protected-modifier-in-oop
  362.             http://stackoverflow.com/questions/37011/should-you-ever-use-protected-member-variables
  363.             http://stackoverflow.com/questions/4913025/reasons-to-use-private-instead-of-protected-for-fields-and-methods
  364.  
  365.             http://www.javalobby.org/java/forums/t77911.html
  366.  
  367.     Просмотри весь проект, перейди на использование public
  368. */
Advertisement
Add Comment
Please, Sign In to add comment