julia_v_iluhina

Untitled

Sep 13th, 2016
95
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 24.99 KB | None | 0 0
  1. src/test/java/framework/
  2.  
  3. /*
  4.     все же framework - слишком громкое название)
  5.  
  6.     давай по сути
  7.  
  8.     все универсальное - будет находиться в ветке проекта src \ main \ java\...\core
  9.     пейджи - это тоже универсальное - будут в ветке      src \ main \ java\...\pages
  10.  
  11.     тест-классы, тестовые данные, предки тест-класса - в ветке src \ test \ java \ ...
  12.  
  13.     в самом конце ревью - будут кусочки на почитать
  14.     про структуру проекта - тоже добавлю
  15. */
  16. **********************************************
  17. public abstract class ConsiceAPI {
  18. /*
  19.     ага, ты добрался до такой версии)
  20.     ок)
  21.     упрощать - не будем)
  22.  
  23.     класс - универсальный
  24.     см выше - думай - где верно расположить в проекте
  25. */
  26.  
  27.     public abstract WebDriver getWebDriver();
  28.  
  29.     public <V> V assertThat(Function<? super WebDriver,V>condition) {
  30.         return (new WebDriverWait(getWebDriver(), 4)).until(condition);
  31.     }
  32.     /*
  33.         реализовал - верно
  34.         можно чуть упростить параметр
  35.         вместо
  36.         Function<? super WebDriver,V>condition
  37.         использовать
  38.         ExpectedCondition<V> condition
  39.  
  40.         такое упрощение допустимо
  41.         т к ExpectedCondition<V> - это потомок вот этого типа Function<? super WebDriver,V>
  42.         (new WebDriverWait(...).until - ждет параметра типа Function<? super WebDriver,V>
  43.  
  44.         и технически - будет все ок
  45.         если вместо значения типа предка - Function<? super WebDriver,V>
  46.         мы передадим значение типа потомка - ExpectedCondition<V>
  47.         а мы только кондишены и намерены передавать
  48.  
  49.         получим - код, который нам понимать полегче
  50.         уже неплохо)
  51.  
  52.  
  53.         что касается таймаута
  54.         тут, в методе, он явно указан равным 4 секунды
  55.         но - ведь нам далеко не всегда таймаут в 4 секунды нужен
  56.  
  57.         для удобства - реализуй метод с вторым параметром - таймаутом - int timeout
  58.  
  59.         так - мы при вызове метода assertThat сможем диктовать - какой таймаут нам нужен
  60.  
  61.         с другой стороны - не удобно каждый раз указывать таймаут
  62.         особенно - если во всех проверках теста нужен какой-то одинаковый таймаут
  63.  
  64.         потому - реализуй второй метод assertThat
  65.         уже с одним параметром - кондишеном
  66.         в котором переиспользуй ранее реализованный
  67.         а в качестве параметра - укажи значение Configuration.timeout
  68.  
  69.         в том же пекедже, рядом с ConciseAPI реализуй класс  Configuration
  70.         там будем хранить всякие настройки
  71.         пока там будет только таймаут timeout - статическое публичое поле
  72.         по умолчанию равное 4 секундам
  73.  
  74.         тогда - если нам в тесте нужно будет использовать в проверках таймаут = 15 секундам
  75.         мы в тест-классе (вспомни код задания про GMail на Selenide) укажем таймаут нужных нам размеров
  76.         лишь единожды изменив значение Configuration.timeout
  77.  
  78.         а assertThat с двумя параметрами - будем использовать только в случаях
  79.         когда для конкретной проверки нужен такой-то таймаут
  80.  
  81.         идем дальше)
  82.         надеюсь, ты разобрался - что сие значит <V> - в сигнатуре єтого метода
  83.         тоже - ниже ревью - приведу кусочки на почитать
  84. */
  85. ************************
  86.  
  87.     public By byCss(String cssSelector) {
  88.         return By.cssSelector(cssSelector);
  89.     }
  90.  
  91.     public By by(String cssSelector) {
  92.         return byCss(cssSelector);
  93.     }
  94. /*
  95.     отличный метод byCss
  96.     думаю, его достаточно
  97.     можно вполне обойтись без метода by
  98. */
  99. *************************************************
  100. public class BaseTest extends ConsiceAPI {
  101.  
  102.     WebDriver driver = new FirefoxDriver();
  103.  
  104.     @After
  105.     public void tearDown() {
  106.         driver.quit();
  107.     }
  108.     public WebDriver getWebDriver() {
  109.         return driver;
  110.     }
  111. }
  112. /*
  113.     ну... можно и так
  114.  
  115.     только ты учти
  116.     в таком варианте - перед стартом каждого теста будет создаваться вебдрайвер
  117.     и после каждого теста - удаляться
  118.  
  119.     если несколько тестов одного тест-класса выполняются в одном потоке - то достаточно
  120.     единожды перед запуском всех тестов - создать вебдрайвер
  121.     и удалить его - после того, как все тесты отработают
  122.  
  123.     надо четко понимать это
  124.     и использовать нужный тебе вариант
  125.  
  126.     на создание вебдрайвера - тоже уходит время и ресурсы
  127.     потому - тут надо отталкиваться от поставленой задачи
  128.  
  129.     проверь - как пишется слово concise
  130.     concise vs consice
  131. */
  132. ************************************************
  133. public class BasePage extends ConsiceAPI {
  134. /*
  135.     к предку пейджей BasePage - вопросов нет
  136.     это - универсальный класс
  137.     расположи правильно (выше писала - что где)
  138. */
  139. ***********************************************
  140. public class GooglePage extends BasePage {
  141.  
  142. ...
  143.     public void followFirstResult(){
  144.         $(firstResult).findElement(by(".r a")).click();
  145.     }
  146. }
  147. /*
  148.     ну, уже отладился - как использовать $(...)
  149.     это ок
  150.  
  151.     теперь - переходим к реализации нашей задачи - gMail
  152.     оттолкнись от своей же селенидовской версии
  153.  
  154.     первое
  155.         перенеси в этот проект пейджи (см ревью выше - где их правильно расположить)
  156.         пейджи отнаследуй от BasePage
  157.         пейджи мы будем использовать в режиме пейджей-объектов -
  158.         потому подправь имена классов пейджей и объявления полей и методов
  159.         (имена классов пейджей-объектов - заканчиваются на Page, поля и методы - не статические)
  160.  
  161.         метод $(...) - уже рабочий, и это ок
  162.         проверки assertMail & assertMails, и саму переменую mails - пока закомментируй
  163.         это сделаем позже
  164.         сначала - реализуем все методы-действия
  165.  
  166.         тебе не хватит методов
  167.             byText
  168.             и
  169.             byTitle
  170.             посмотри - как они реализованы в селениде
  171.             фактически - вызывается By.xPath(...) с правильным аргументом
  172.             какой это - правильный аргумент - можно как раз в Selenide подсмотреть
  173.             ну или самостоятельно написать xPath-выражение
  174.  
  175.         что использовать
  176.         вместо - setValue(text) или pressEnter()  для вебэлемента -
  177.         думаю, догадаешься
  178.         предыдущие работы по селениуму в помощь
  179.  
  180.     второе
  181.         перенеси класс с тестовыми данными и тест-класс
  182.         правильно изх расположи
  183.         тест-класс - отнаследуй от BaseTest
  184.         правильно инициализируй пейджи
  185.         в GoogleTest - пример есть
  186.         настрой Configuration.timeout (в селенидовской версии - пример есть)
  187.  
  188.         реализуй весь сценарий (за исключением проверок)
  189.         цель - получить работающий сценарий -
  190.         залогинились, отправили письмо, обновили, перешли в отправленные,
  191.         вернулись во входящие, поискали
  192.  
  193.         проверки - пока закомментируй
  194.  
  195.         цель номер один - получить вот это
  196.    
  197.     !!! - зафиксируй в репозитории версию
  198.  
  199.     !!! если это окажется не сложным -  продолжай
  200.  
  201.         определись - какую первую версию ты хочешь делать
  202.         это - последняя работа
  203.         где еще можно применить @FindBy элементы
  204.         потому - советую с ними потренироваться
  205.        
  206.         потому в пейдже
  207.         заведи @FindBy переменную для списка мейлов (селектор ты знаешь - см селенидовскую работу)
  208.    
  209.         и пришла пора реализовывать проверки)
  210.         будем проверять список мейлов
  211.         нам нужны новых 2 кондишена для проверки списка мейлов
  212.         в assertMail - assertThat(nthElementHasText(mails, 0, mailText))
  213.         в assertMails - assertThat(textsOf(mails, mailTexts))
  214.        
  215.         nthElementHasText -
  216.         получить элемент с индексом ...
  217.         и текст этого элемента
  218.         проверь текст этого элемента на соответствие переданному
  219.        
  220.         textsOf
  221.         получить тексты всех элементов
  222.         сверить количество текстов фактических и переданных в кондишен (ожидаемых)
  223.         если количество не равно - проверка не прошла
  224.         если количество равно - сверяешь попарно тексты - нулевой фактический с нулевым ожидаемым,
  225.         первый - с первым и т д
  226.         если тексты соответствуют - продолжаем проверять
  227.         если не соответствуют - уже проверка не прошла
  228.         если все тексты соответствуют - проверка прошла
  229.        
  230.         логику обоих кондишенов кратко я описала
  231.         открой селениумский модуль ExpectedConditions (напиши в коде ExpectedConditions и, зажав ctrl, кликни)
  232.         и посмотри - как устроены стандартные селениумские кондишены
  233.         посмотри предыдущие задания - повспоминай - как ты писал кондишены попроще
  234.        
  235.         по идее - на этом этапе - точно должны появиться вопросы)
  236.         постарайся - получить список максимально конкретных вопросов
  237.         в любом случае, разберем - любые
  238.         но - пока будешь писать эти вопросы - многое сам поймешь и разберешь)
  239.        
  240.         вопросы собирай в отдельый список
  241.         потом списком же - и отдашь мне
  242.         хоть в pastebin выложи
  243.         хоть код комментируй - вопросы пиши
  244.         хоть - планируй голосовое общение
  245.         все варианты годятся
  246. */
  247.  
  248. *************************************************
  249. ***************на почитать***********************
  250. *************************************************
  251. /*
  252.     http://joxi.ru/nAyqEx7HXvxQoA
  253.  
  254.     вот пример хорошей структуры проекта
  255.  
  256.     в src \ main
  257.  
  258.       core - универсальное, что можно переиспользовать в разных проектах
  259.       pages - пейджи тоже можно переиспользовать для других тестов этого же приложения
  260.  
  261.  
  262.     в src \ test
  263.  
  264.       testdata - тестовые данные (если такие есть и они вынесены в отдельный класс)
  265.       testconfigs - предки тест-класса (так можно их изолировать от  собственно тест-классов - чтоб легче было ориентироваться
  266.  
  267.  
  268.     про пекеджи еще немного)
  269.     если GroupID = com.somesite
  270.     а проект todomvctest
  271.     то пакет корневой должен быть com.somesite.todomvctest
  272.  
  273.     логика  - чтобы "не смешивались имена сущностей"
  274.  
  275.     внутри одной компании - может быть несколько проектов)
  276.     и у всех у них один com.somesite  - базовый пекедж
  277.     но для каждого проекта должен быть свой  “базовый пекедж проекта"
  278.     иначе все смешается)
  279.     важно то, что когда этот проект выльется в отдельную библиотеку,
  280.     то не будет конфликтов при его подключении
  281. */
  282. ********************
  283.  
  284. /*
  285.  Кодишенов есть много и разных
  286.     и далеко не все они ExpectedCondition<Boolean>
  287.     вот в этих <...> - могут быть разные типы
  288.     если совсем грубо - то результат вот этого ... типа и вернет нам WebDriverWait(...).until(...) -
  289.  
  290.     например
  291.          есть такой кондишен ExpectedCondition<WebElement> visibilityOfElementLocated(By locator)
  292.          https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html#visibilityOfElementLocated-org.openqa.selenium.By-
  293.  
  294.          это значит WebDriverWait(...).until(visibilityOfElementLocated(...)) - вернет вебэлемент, видимость которого мы ждали
  295.  
  296.          а для кондишенов ExpectedCondition<Boolean> - new WebDriverWait(...).until вернет результат типа Boolean
  297.  
  298.          это не отменяет главной схемы работы - если проверка new WebDriverWait(...).until( - не проходит за таймаут -
  299.          то вызывается исключение
  300.  
  301.          но - помимо этого - есть вот такая разница ...
  302.  
  303.     пока наш assertThat возвращает void  - нас это может не сильно тревожить )
  304.     достаточно - в описании параметров убрать уточнение типа - не ExpectedCondition<Boolean>, а ExpectedCondition
  305.     и assertThat - будет работать с любым из кондишенов
  306.     правда - ничего нам не вернет)
  307.  
  308.     а вот если хочется получить результат new WebDriverWait(...).until( -
  309.     да еще и не городить кучу методов - придется подумать и немного теории почитать
  310.  
  311. */
  312. *******
  313. /*
  314.         assertThat(visibilityOf(composeButton), driver);
  315.                 composeButton.click();
  316.  
  317.         код такого типа можно записать в одну строку
  318.  
  319.         типа вот так:
  320.  
  321.                 assertThat(visibilityOf(composeButton), driver).click();
  322.  
  323.         точнее... можно было бы... если бы ты "правильно обернула метода wait.until" внутрь assertThat
  324.  
  325.         то есть, оригинальный код:
  326.  
  327.                 wait.until(visibilityOf(composeButton)).click()
  328.  
  329.         будет работать. Тебе просто нужно сделать так, что бы assertThat возвращал не void а то же что возвращает wait.until
  330.  
  331.         А что же он возвращает?
  332.  
  333.         Давай разберемся. Сначала "идейно".
  334.  
  335.         Этот метод until возвращает такую интересную динамическую штуку-аватар...
  336.         "воплощение" которого зависит от того что именно ты передашь вейт антилу параметром
  337.         - точнее - какой именно кондишен ты ему передаешь...
  338.  
  339.         А кондишены бывают "разные"... "Разность" эта определеятся "параметром типа" который в джава записывается ИмяТипа<ЗДЕСЬ>
  340.  
  341.         Ты уже ведь использовала списки например... В частности
  342.  
  343.         List<WebElement>
  344.  
  345.         вот в такой записи типа - его параметром, выступает WebElement, указывая джаве,
  346.         что это не просто список а "список ВебЕлементов"
  347.         а мог бы быть и списком стрингов например - List<String> или еще чего :)
  348.  
  349.         Такие "умные" типы которые получают параметр (или больше) - так и называются - параметризироваными
  350.         (а фича языка в которой они поддерживаются называется - параметрическим полиформизмом - не путать с тем другим полиморфмизом... который называется - subtyping polymorphism а в джава все его знают как просто "полиморфизм")... Еще они называются - шаблоны... или дженерики... Именно так - Java Generics - их принято называть в Java
  351.  
  352.         Так вот... таким же дженериком является тип ExpectedCondition
  353.         который может быть параметризирован...
  354.         Ты уже встречала запись типа:
  355.  
  356.         ExpectedCondition<Boolean>
  357.  
  358.         что же значит этот булеан? что он параметризирует?
  359.  
  360.         А он параметризирует внутреннюю реализацию этого кондишена...
  361.  
  362.         Он определяет то каким должен быть тип возвращаемого значения в методе apply
  363.  
  364.         То есть...
  365.         Если ты поставишь цель создать кондишен ExpectedCondition<Boolean> - ты должна будешь реализовать
  366.         его метод apply -  как возвращающий тип Boolean
  367.  
  368.         Но зачем вообще нам парится о типе возвращаемой сущности метода apply?
  369.  
  370.         А потому что есть еще один "умный дженерик"... Только который не "параметризированный клас" а "параметризированный метод"
  371.         (в джава бывают как Generic Types так и Generic Methods)
  372.  
  373.         и этот параметризированный метод - как раз и есть наш wait.until
  374.  
  375.         особенность реализации этого метода в том... что он вызывает внутри метод apply
  376.         нашего кондишена... и запоминает то значение которое этот метод apply возвращает...
  377.         И потом... в конце всей истории... этот метод until - либо бросит исключение (в случае если "не дождется" кондишена)
  378.         либо вернет то что вернул метод apply в "случае успеха"...
  379.  
  380.         Получается... Если ты передашь вейт антилу кондишен параметризированный типом Boolean
  381.         то в случае успеха антил - вернет тру...
  382.  
  383.         то есть ты можешь писать код вида:
  384.  
  385.         if (wait.until(enabled(composeButton))) {
  386.            doSomething();
  387.         }
  388.  
  389.         но на самом деле такое нужно не часто... то есть - такие кондишены - которые
  390.         параметризированы типом булеан...
  391.  
  392.         бошьше толку как раз от кондишенов параметризированных типом "того, характеристики чего ждет кондишен"...
  393.  
  394.         вот кондишен visibilityOf - как раз параметризирован типом WebElement
  395.             ExpectedCondition<WebElement>
  396.  
  397.         и его метод apply возвращает тип обьект типа WebElement,
  398.         а "идейно" - возвращает этот же элемент визибилити которого мы дожидались...
  399.         (если бы мы не дождались - apply вернул бы null - что в этом случае играет роль "false")
  400.  
  401.         а until в конце концов вернет то что вернет apply
  402.         и именно поэтому мы можем писать такой код:
  403.  
  404.             wait.until(visibilityOf(composeButton)).click()
  405.  
  406.         лучше реализовывать все свои кондишены, чтобы они были параметризированы типом той сущности,
  407.         характеристики, которой они должни дожидаться
  408.         (кстати, так выражатся немного некорректно - ведь кондишен не ждет,
  409.         он только выдает информацию - да/нет - а ждет уже вейт антил, ну то такое:) )
  410.  
  411.         для того что бы "правильно реализовать этот wait.until" - тебе придется разобраться с этими дженериками...
  412.         И с дженерик типами и дженерик методами.
  413.  
  414. */
  415. *****
  416. /*
  417.     про дженерики в общем(русский)
  418.     http://www.quizful.net/post/java-generics-tutorial
  419.  
  420.     http://www.tutorialspoint.com/java/java_generics.htm
  421.     http://developer.alexanderklimov.ru/android/java/generic.php
  422.  
  423.     конвеншенcы      http://stackoverflow.com/questions/2900881/generic-type-parameter-naming-convention-for-java-with-multiple-chars
  424.     https://docs.oracle.com/javase/tutorial/java/generics/types.html
  425.  
  426.     уроки
  427.     http://docs.oracle.com/javase/tutorial/extra/generics/index.html
  428.  
  429.     очень приличный faq (есть pdf, и есть кое-что еще, помимо дженериков)
  430.     http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html
  431.  
  432. */
Advertisement
Add Comment
Please, Sign In to add comment