julia_v_iluhina

Untitled

Sep 7th, 2016
109
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 22.33 KB | None | 0 0
  1.     public <V> V assertThat(ExpectedCondition<V> condition) {
  2.         return (new WebDriverWait(getWebDriver(), 20)).until(condition);
  3.     }
  4. /*
  5.     тут - уже почти ок)
  6.  
  7.     надо добавить немного гибкости
  8.  
  9.     ведь не всегда таймаут именно такого размера требуется
  10.  
  11.     если
  12.     реализовать assertThat со вторым параметром - таймаутом
  13.     то
  14.     можно будет при вызове проверки  - явно указывать размер таймаута
  15.     это бывает удобно - когда в проекте есть проверки, требующие какого-то не стандартного таймаута
  16.  
  17.     в то же время
  18.     для всех проверок указывать аймаут - уже перебор)
  19.     потому - реализуем второй assertThat - уже без параметра - таймута
  20.     в нем - вызовем первый assertThat и в качестве таймаута укажем значение Configuration.timeout
  21.     Тут же, в core, реализуем класс Configuration со статическим полем timeout,
  22.     в котором будет задан таймаут по умолчанию (разумно его установить равным 4 секунды)
  23.  
  24.     А если для тестов значения по умолчанию Configuration.timeout недостаточно
  25.     то всегда есть возможность в  тест-классе настроить самостоятельно Configuration.timeout
  26.  
  27.     Собственно - мы аналогично поступали - когда реализовывали версию этого задания на Selenide
  28.     мы для этого теста изменяли значение Configuration.timeout
  29. */
  30. *********************************
  31. public abstract class ConsizeAPI {
  32. /*
  33.     Con__c__i__s___e
  34.  
  35.     2 буквы поправь)
  36.  
  37.     ошибки спеллинга IntelIJ Idea подчеркивает зеленой волнистой линией - обрати внимание
  38. */
  39. **************************************
  40. public static ExpectedCondition<Boolean> text(final int index, final By elementLocator, final String expectedText) {
  41. /*
  42.     для этого кондишена лучше чуть подробнее имя использовть
  43.  
  44.     listNthElementHasText - к примеру
  45.  
  46.     этот кондишен можно было бы реализовать как
  47.     ExpectedCondition<WebElement>
  48.     или
  49.     ExpectedCondition<List<WebElement>>
  50.  
  51.  
  52.     при работе apply  этого или других кондишенов - могут возникать исключения
  53.  
  54.     в частности - в этом кондишене - может возникнуть
  55.     IndexOutOfBoundsException
  56.     при пролучении элемента списка за его границами
  57.  
  58.     почитай вот это
  59.     https://docs.google.com/document/d/1BiYTLdypDfucSqiY9isv1HCKKQIxelzqYrN-3Ku1RWM/edit?usp=sharing
  60.  
  61.     это - метод, который позволит не использовать в каждом из кондишенов try-catch секции
  62.     общее замечание - у кетчера можно будет
  63.     вместо параметра final Function<? super WebDriver, V> condition
  64.     использовать более простой для понимания ExpectedCondition<V>
  65.  
  66.     Function<? super WebDriver, V> - это предок для ExpectedCondition<V>
  67.     и значение такого типа - принимает until (WebDriverWait)
  68.  
  69.     ниже - приведу информацию - чтобы получше разобраться с таким решением
  70. */
  71. ********************
  72.  
  73.   public static ExpectedCondition<Boolean> text(final int index, final By elementLocator, final String expectedText) {
  74. ....
  75.             public String toString() {
  76.                 return String.format("\n %s -th element in locator %s\n should have text: %s\n while actual text is: %s\n",
  77.                         index, elementLocator, expectedText, actualTexts.get(index));
  78.             }
  79. /*
  80.     не надо в toString() выводить actualTexts.get(index)
  81.     не факт  - что такой элемент есть в списке
  82.     может возникнуть исключение IndexOutOfBoundsException и
  83.     сообщение об ошибке будет скомканным
  84.  
  85.     тут - раз уж у тебя есть все фактические тексты списка элементов - полезнее вывести
  86.     список целиком actualTexts
  87. */
  88. ******************************
  89.                 actualTexts = new ArrayList<String>();
  90.  
  91.                 for (WebElement element : elements) {
  92.                     actualTexts.add(element.getText());
  93.                 }
  94. /*
  95.     Этот код используется в 2-ух кондишенах
  96.  
  97.     реализуй метод List<String> getTexts(List<WebElements>)
  98.     и примени его тут
  99.  
  100.     сам метод - размести в классе-контейнере универсальіх статических методов Helpers
  101. */
  102. *********************************
  103. public class BasePage extends ConsizeAPI
  104. /*
  105.     BasePage - реализован верно
  106.  
  107.     размести его в core
  108.     т к у него - универсальная функциональность
  109.  
  110.     реформатируй код - выравнивание отличается от стандартного
  111. */
  112. ************************************
  113.  
  114. public class BaseTest extends ConsizeAPI {
  115.  
  116.     WebDriver driver = new FirefoxDriver();
  117.  
  118.     @Before
  119.     public void driverOpen() {
  120.         driver.get("http://gmail.com/");
  121.     }
  122.  
  123.     @After
  124.     public void driverQuit() {
  125.         driver.quit();
  126.     }
  127. /*
  128.     ну да, можно и так
  129.  
  130.     важно - чтоб ты понимала - когда какой вариант тебе нужен
  131.  
  132.     в варианте
  133.         создание вебдрайвера
  134.             инициализация не статического поля
  135.             или
  136.             instance initialization block
  137.             или
  138.             @Before-метод
  139.         удаление вебдрайвера
  140.             @After-метод
  141.         все ОК
  142.             перед каждым тестом - делаем новый вебдрайвер
  143.             после каждого теста - удаляем его
  144.  
  145.     есть еще рабочий вариант
  146.         создание вебдрайвера
  147.             инициализация статического поля
  148.             или
  149.             static initialization block
  150.             или
  151.             @BeforeClass-метод
  152.         удаление вебдрайвера
  153.             @AfterClass-метод
  154.         все ОК
  155.             перед запуском всех тестов класса (единожды) - делаем новый вебдрайвер
  156.             после выполнения всех тестов класса (единожды) - удаляем его
  157.  
  158.      важно - чтобы создание-удаление вебдрайвера выполнялось соотвественно друг другу
  159.             описанные выше варианты - ок
  160.  
  161.             а если создавать вебдрайвер перед каждым тестом в @Before-методе,
  162.             а удалять - после выполнения всех тестов @AfterClass-методе
  163.             то получится - ерунда
  164.             будут оставаться открытые браузеры
  165.  
  166.             а вот какой из рабочих вариантов выбрать - надо исходить из текущих задач
  167.             если тесты одного класса не выполняются в параллельном режиме - то достаточно
  168.             единожды создать и удалить вебдрайвер - на все тесты этого класса
  169.             при параллельном запуске - конечно, на каждый тест будет нужен свой вебдрайвер
  170.  
  171.             так что - тут бы я все же использовала @BeforeClass + @AfterClass
  172.             так поэкономнее)
  173.             хотя - пока у нас единственный тест-метод - по большому счету - разницы мы не увидим
  174.  
  175.             просто - про такие вещи лучше сразу думать
  176.  
  177.      можешь оставить как есть, можешь переделать на вариант с @BeforeClass + @AfterClass
  178.      важно - чтоб было понимание
  179. */
  180. **************************************************************************
  181.  
  182. /*
  183.     дальше - кусочки, шире раскрывающие тему
  184.     для понимания, а не для выполнения
  185.    
  186.     почитай, поразбирайся
  187. */
  188.  
  189. /*
  190.         instance initialization block - будет выполняться перед запуском каждого тест-метода
  191.         static initialization block - перед запуском всех тест-методов тест-класса
  192.  
  193.         http://www.javamadesoeasy.com/2015/06/differences-between-instance.html
  194.  
  195.         разница по эффекту - как использовать @Before или  @BeforeClass метод
  196. */
  197.  
  198. /*
  199.     BeforeClass vs static initialization block
  200.     http://stackoverflow.com/questions/15493189/beforeclass-vs-static
  201.  
  202.     Получим более содержательное сообщение об ошибке - если работаем с аннотированными методами
  203.  
  204.     http://www.unknownerror.org/opensource/junit-team/junit/q/stackoverflow/512184/best-practice-initialize-junit-class-fields-in-setup-or-at-declaration
  205.  
  206.     про ругань красивую - http://www.javaworld.com/article/2076265/testing-debugging/junit-best-practices.html
  207.     (подзаголовок Do not use the test-case constructor to set up a test case)
  208.  
  209. */
  210.  
  211. ****
  212.  
  213. /*
  214.     это по нашему с тобой вчерашнему разговору,
  215.     все то же, что ты уже применила - т е ДЕЛАТЬ НИЧЕГО НЕ НАДО )
  216.     ты уже это сделала )
  217.    
  218.     возможно - полезно будет почитать
  219. */
  220.  
  221. /*
  222.   Кодишенов есть много и разных
  223.     и далеко не все они ExpectedCondition<Boolean>
  224.     вот в этих <...> - могут быть разные типы
  225.     если совсем грубо - то результат вот этого ... типа и вернет нам WebDriverWait(...).until(...) -
  226.  
  227.     например
  228.          есть такой кондишен ExpectedCondition<WebElement> visibilityOfElementLocated(By locator)
  229.          https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html#visibilityOfElementLocated-org.openqa.selenium.By-
  230.  
  231.          это значит WebDriverWait(...).until(visibilityOfElementLocated(...)) - вернет вебэлемент, видимость которого мы ждали
  232.  
  233.          а для кондишенов ExpectedCondition<Boolean> - new WebDriverWait(...).until вернет результат типа Boolean
  234.  
  235.          это не отменяет главной схемы работы - если проверка new WebDriverWait(...).until( - не проходит за таймаут -
  236.          то вызывается исключение
  237.  
  238.          но - помимо этого - есть вот такая разница ...
  239.  
  240.     пока наш assertThat возвращает void  - нас это может не сильно тревожить )
  241.     достаточно - в описании параметров убрать уточнение типа - не ExpectedCondition<Boolean>, а ExpectedCondition
  242.     и assertThat - будет работать с любым из кондишенов
  243.     правда - ничего нам не вернет)
  244.  
  245.     а вот если хочется получить результат new WebDriverWait(...).until( -
  246.     да еще и не городить кучу методов - придется подумать и немного теории почитать
  247. */
  248.  
  249.     public static WebElement $(WebDriver driver, By elementLocator) {
  250.         assertThat(driver, visibilityOfElementLocated(elementLocator));
  251.         return driver.findElement(elementLocator);
  252.     }
  253. /*
  254.     вот этот кондишен visibilityOfElementLocated - типа ExpectedCondition<WebElement>
  255.     значит - если бы assertThat возвращал то же, что и new WebDriverWait(...).until(...)
  256.  
  257.     то - assertThat вернул бы вебэлемент
  258.     и нам не пришлось бы его искать дополнительно
  259.     и метод выглядел бы вот так
  260. */
  261.     public static WebElement $(WebDriver driver, By elementLocator) {
  262.         return assertThat(driver, visibilityOfElementLocated(elementLocator));
  263.     }
  264. /*
  265.     Это не единственный вариант, когда нам это может пригодиться
  266.     но для самого простого и полезного примера - самое то)
  267.  
  268.     теперь - как этого добиться
  269. */
  270. /*
  271. Давай разберемся. Сначала "идейно".
  272.  
  273. Этот метод until возвращает такую интересную динамическую штуку-аватар...
  274. "воплощение" которого зависит от того что именно ты передашь вейт антилу параметром
  275. - точнее - какой именно кондишен ты ему передаешь...
  276.  
  277. А кондишены бывают "разные"... "Разность" эта определеятся "параметром типа" который в джава записывается
  278. ИмяТипа<ЗДЕСЬ>
  279.  
  280. Ты уже ведь использовал списки, например...
  281. В частности - List<WebElement>
  282.  
  283. вот в такой записи типа - его параметром, выступает WebElement, указывая джаве,
  284. что это не просто список, а "список ВебЕлементов"
  285. а мог бы быть и списком стрингов например - List<String> или еще чего :)
  286.  
  287. Такие "умные" типы которые получают параметр (или несколько параметров) - так и называются - параметризированными
  288. (а фича языка, в которой они поддерживаются называется - параметрическим полиформизмом -
  289. не путать с тем другим полиморфмизом... который называется - subtyping polymorphism,
  290. а в джава все его знают как просто "полиморфизм")...
  291. Еще они называются - шаблоны... или дженерики...
  292. Именно так - Java Generics - их принято называть в Java
  293.  
  294. Так вот... таким же дженериком является тип ExpectedCondition
  295. который может быть параметризирован...
  296.  
  297. Ты уже встречал запись типа:
  298. ExpectedCondition<Boolean>
  299.  
  300. что же значит этот булеан? что он параметризирует?
  301. А он параметризирует внутреннюю реализацию этого кондишена...
  302. Он определяет то, каким должен быть тип возвращаемого значения в методе apply
  303.  
  304. То есть...
  305. Если ты поставишь цель создать кондишен ExpectedCondition<Boolean> - ты должен будешь реализовать
  306. его метод apply -  как возвращающий тип Boolean
  307.  
  308. Но зачем вообще нам париться о типе возвращаемой сущности метода apply?
  309.  
  310. А потому, что есть еще один "умный дженерик"...
  311. Только который не "параметризированный класс", а "параметризированный метод"
  312. (в джава бывают как Generic Types так и Generic Methods)
  313.  
  314. и этот параметризированный метод - как раз и есть наш wait.until
  315.  
  316. особенность реализации этого метода в том... что он вызывает внутри метод apply
  317. нашего кондишена... и запоминает то значение, которое этот метод apply возвращает...
  318.  
  319. И потом... в конце всей истории... этот метод until - либо бросит исключение
  320. (в случае если "не дождется" кондишена)
  321. либо вернет то, что вернул метод apply в "случае успеха"...
  322.  
  323. Получается... Если ты передашь вейт антилу кондишен параметризированный типом Boolean
  324. то в случае успеха антил - вернет тру...
  325.  
  326. то есть ты можешь писать код вида:
  327.  
  328. if (wait.until(enabled(composeButton))) {
  329.    doSomething();
  330. }
  331.  
  332. но на самом деле, такое нужно не часто...
  333. то есть - такие кондишены - которые
  334. параметризированы типом булеан...
  335.  
  336. бошьше толку как раз от кондишенов параметризированных типом "того, характеристики чего ждет кондишен"...
  337.  
  338. вот кондишен visibilityOf - как раз параметризирован типом WebElement
  339.     ExpectedCondition<WebElement>
  340.  
  341. и его метод apply возвращает обьект типа WebElement,
  342. а "идейно" - возвращает этот же элемент, визибилити которого мы дожидались...
  343. (если бы мы не дождались - apply вернул бы null - что в этом случае играет роль "false")
  344.  
  345. а until в конце концов вернет то, что вернет apply
  346. и именно поэтому мы можем писать такой код:
  347.  
  348.     wait.until(visibilityOf(composeButton)).click()
  349.  
  350. теперь твоим заданием будет - переделать assertThat что бы он возвращал то что возвращает wait.until
  351.  
  352. ну и потом - переделать все свои кондишены, что бы они были параметризированы типом той сущности,
  353. характеристики которой они должни дожидаться (кстати так выражатся немного некорректно - ведь кондишен не ждет,
  354. он только выдает информацию - да/нет - а ждет уже вейт антил, ну то такое:) )
  355.  
  356. для того, чтобы "правильно реализовать этот wait.until" -
  357. тебе придется разобраться с этими дженериками...
  358. И с дженерик типами и дженерик методами.
  359.  
  360. И даже этого будет мало...
  361. Прийдется покопаться в коде селениума, чтобы понять, что там за тип реально получает
  362. вейт антил как кондишен...
  363. Потому что он получает не ExpectedCondition а что то еще более странное...
  364. Это работает - потому что это "странное" - есть родительским классом для ExpectedCondition
  365.  
  366. */
  367.  
  368. /*
  369.     Что почитать про Generics
  370.     про дженерики в общем(русский)
  371.     http://www.quizful.net/post/java-generics-tutorial
  372.  
  373.     http://www.tutorialspoint.com/java/java_generics.htm
  374.     http://developer.alexanderklimov.ru/android/java/generic.php
  375.  
  376.     конвеншенcы      http://stackoverflow.com/questions/2900881/generic-type-parameter-naming-convention-for-java-with-multiple-chars
  377.     https://docs.oracle.com/javase/tutorial/java/generics/types.html
  378.  
  379.     уроки
  380.     http://docs.oracle.com/javase/tutorial/extra/generics/index.html
  381.  
  382.     очень приличный faq (есть pdf, и есть кое-что еще, помимо дженериков)
  383.     http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html
  384.  
  385.     ----------------------------------------------------------
  386.     для понимания кетчера (Catcher)
  387.     http://grepcode.com/file/repo1.maven.org/maven2/com.google.guava/guava/r06/com/google/common/base/Function.java
  388.     http://www.programcreek.com/java-api-examples/com.google.common.base.Function
  389.     https://docs.oracle.com/javase/tutorial/java/generics/lowerBounded.html
  390.     http://stackoverflow.com/questions/3847162/java-generics-super-keyword
  391.     http://stackoverflow.com/questions/2800369/bounding-generics-with-super-keyword
  392.     http://stackoverflow.com/questions/1910892/what-is-the-difference-between-super-and-extends-in-java-generics
  393.  
  394.     если осилишь после этого и применение кетчера(то, что в прошлом ревью отложили) - можно уже сейчас
  395.     по-прежнему - кетчера можно отложить
  396. */
Advertisement
Add Comment
Please, Sign In to add comment