Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <dependencies>
- <dependency>
- <groupId>com.codeborne</groupId>
- <artifactId>selenide</artifactId>
- <version>3.6</version>
- </dependency>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.12</version>
- </dependency>
- <dependency>
- <groupId>ru.yandex.qatools.allure</groupId>
- <artifactId>allure-junit-adaptor</artifactId>
- <version>${allure.version}</version>
- </dependency>
- </dependencies>
- /*
- pom - только селениум тебе нужен
- в предыдущих заданиях - у тебя же есть примеры хорошего pom-а
- */
- ************************************************
- public abstract class ConciseApi {
- public abstract WebDriver getWebDriver();
- /*
- ага, у тебя сразу получается версия следующей работы)
- ок - упрощать не будем)
- */
- *************************************************
- public WebElement $(WebDriver driver ,By locator){
- return assertThat(driver ,ExpectedConditions.visibilityOfElementLocated((locator)));
- }
- /*
- в методе ты можешь использовать getWebDriver() и параметра WebDriver driver - уже не нужно
- собственно - идея без наследования,
- но с параметром WebDriver driver во всех методах - это как раз вариант наиболее простой реализации задания
- упрощать смысла нету)
- используй import static - для ExpectedConditions.visibilityOfElementLocated
- тогда в коде будет полаконичнее - visibilityOfElementLocated
- двойные скобки ((locator)) - можно упростить
- достаточно (locator)
- */
- ******************************************************************
- public WebElement $(WebDriver driver ,String cssSelector){
- /*
- тут - тоже
- избавься от параметра WebDriver driver
- и в реализации - вызывай $(WebDriver driver ,By locator)
- это даст более DRY код
- выгоды - как обычно
- чуть более DRY код
- чуть лаконичнее
- чуть проще для понимания (понимать один код вместо двух)
- чуть проще для сопровождения (менять один код вместо двух)
- */
- ***************************************************
- public static int timeout =4;
- ...
- public <T> T assertThat(WebDriver driver,ExpectedCondition<T> condition) {
- /*
- много хороших идей
- то, что вынес в переменную - таймаут
- то, что в реализации метода используешь дженерик тип
- по реализации - чуть поправим
- WebDriver driver - можно убрать параметр
- реализуй метод public <T> T assertThat(ExpectedCondition<T> condition, int timeout)
- и второй метод - public <T> T assertThat(ExpectedCondition<T> condition)
- в котором - используй настроечную переменную timeout и первій метод
- только еще и для настроечной переменной timeout
- реализуй класс Configuration
- именно там будем собирать все настроечніе переменные
- пока - будет только timeout
- чего мы в результате добьемся
- во-первых - разделим настройки и инструменты - по разным классам
- почитай про single responsibility principle
- во-вторых - у нас будет метод assertThat(ExpectedCondition<T> condition, int timeout)
- чтоб вызывать в случаях, когда надо явно задать таймаут
- (например, везде ждем 4 секунды, и только какую-то одну проверку - нужен бОльший таймаут)
- в-третьих - у нас будет assertThat(ExpectedCondition<T> condition)
- который будет оперировать таймаутом из настроек
- что тоже удобно
- раз перед тестами при необходимости - настроили таймаут
- и все проверки выполняются с таким таймаутом
- и ниже - приведу полезное на почитать про джереники, вдруг что-то из этого пригодится
- */
- *****************************************************************
- public class BaseTest extends ConciseApi {
- public WebDriver driver;
- @Before
- public void startUP(){
- driver = new FirefoxDriver();
- }
- @After
- public void tearDown(){
- driver.close();
- }
- /*
- да, можно и так)
- перед запуском каждого тест-метода - создавать вебдрайвер
- и после каждого тест-метода - его удалять
- правда, не всегда это нужно
- надо исходить из текущих потребностей
- если все тесты отрабатывают в одном потоке - то разумнее
- перед запуском всех тестов - единожды создавать вебдрайвер
- и после работы всех тестов - удиножды удалять
- в таком случае тебе нужна пара BeforeClass & AfterClass методов
- напоминаю - они статические, и переменная driver - тоже должна быть статической в таком случае
- а что вызвать для вебдрайвера - close vs quit - почитай)
- http://stackoverflow.com/questions/15067107/difference-between-webdriver-dispose-close-and-quit
- http://www.testingdiaries.com/driver-close-and-driver-quit/
- http://internetka.in.ua/selenium-webdriver-quit-or-close/
- про имя метода - startUP() - написание по lowerCamelCase должно быть
- */
- ***********************************************
- public class BasePage extends ConciseApi {
- /*
- этот класс-предок для пейджей - универсальный
- потому его можно перенести в core
- важно - предок тест-класса - пусть и универсальный -
- все авно располагаем в ветке src \ test
- */
- *************************************************************
- @Step
- public void assertMail(int index, String mailText) {
- Assert.assertEquals((mails.get(index).getText()), mailText);
- }
- /*
- Assert.assertEquals - не ждущая проверка
- так - проверять не надежно
- лучше - реализовать кондишен listNthElementHasText(List<WebElement> elements, int index, String expectedText)
- и проверять тут - с помощью ждущей проверки - с использованием этого кондишена
- суть проверки
- получаем такой-то элемент списка
- у него - его текст
- если текст содержит expectedText - значит проверка прошла
- если нет - значит - не прошла
- */
- ************************************
- ...
- //mails.assertMailTexts(subject);
- /*
- и для реализации этой проверки нужен кондишен
- аналог texts в селениде
- тут у тебя будет textsOf(List<WebElement> elements,String... expectedTexts)
- схема проверки та же
- получили тексты всех элементов списка
- сравнили размер списка с фактическими текстами с коичеством переданных текстов
- если не равны - проверка не прошла
- если равны - сравниваем тексты попарно - нулевой - с нулевым, первый - с первым и т д
- если фактический текст содержит ожидаемый - проверяем дальше
- иначе - при первом не сопадении - проверка не прошла
- а если проверили все пары и все ок - проверка прошла
- т е - проверили - количество, порядок и сами тексты
- а в toString кондишена
- выводи - что проверял + для чего проверял
- что ждали
- и что получили
- и вот тут тебе и пригодится собранные в список фактические тексты элементов списка
- подсказки по логике - можно подсмотреть в кондишене texts - селенидовском
- подсказки по селениумским кондишенам - можно подсмотреть в классе ExpectedConditions
- (напиши в коде + зажми ctrl + кликни = откроется исходній код)
- есть еще моменты
- в процессе выполнения кода в apply - могут возникать исключения
- это надо обрабатывать
- попробуй переварить вот это
- https://docs.google.com/document/d/1BiYTLdypDfucSqiY9isv1HCKKQIxelzqYrN-3Ku1RWM/edit?usp=sharing
- в качестве параметра этого кетчера - можно применять ExpectedCondition<V> condition
- ниже - будут пояснения - почему
- если про кетчера - пока не понятно - постарайся осознать - что ряд исключений надо ловить в apply кондишена
- и это применить
- вообще - работы пошли уже не простые)
- приходи в слек, я ежедневно есть - после 21-00
- и во второй половине дня в будние дни
- многое в режиме вопросов-ответов - разберем
- здесь и далее - это уже будет нормой)
- */
- ***********************************
- @Step
- public void goToInbox(){
- $(getWebDriver(), byText("Входящие")).click();
- }
- /*
- тут тоже интересно)
- если искать по тексту - как правило - происходит клик не на линке - папка Входящие
- а на первом письме из списка отправленных (потому что есть такой текст в описании письма)
- тебе нужна реализация byTitle(...)
- это можно в селениде подсмотреть
- и еще
- если во входящих есть не прочитанные - byTitle(...), организованный как в селениде - не сработает
- т к поиск текста - не по вхождению, а по равенству
- надо бы адаптировать)
- в faq - есть полезные таблички по xPath-у
- https://docs.google.com/document/d/13dNyFGbI7mV22UUhH8E0LJ7SzabAmX7Bw7VCHScYfiU/edit#bookmark=id.lirnyzxrth5n
- советую скачать и пользоваться)
- */
- ******************************************************************
- *********************************************************************
- ***********************************************************************
- /*
- это на почитать
- возможно - ты и так это уже разобрал
- привожу на всякий случай
- */
- /*
- Кодишенов есть много и разных
- и далеко не все они ExpectedCondition<Boolean>
- вот в этих <...> - могут быть разные типы
- если совсем грубо - то результат вот этого ... типа и вернет нам WebDriverWait(...).until(...) -
- например
- есть такой кондишен ExpectedCondition<WebElement> visibilityOfElementLocated(By locator)
- https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html#visibilityOfElementLocated-org.openqa.selenium.By-
- это значит WebDriverWait(...).until(visibilityOfElementLocated(...)) - вернет вебэлемент, видимость которого мы ждали
- а для кондишенов ExpectedCondition<Boolean> - new WebDriverWait(...).until вернет результат типа Boolean
- это не отменяет главной схемы работы - если проверка new WebDriverWait(...).until( - не проходит за таймаут -
- то вызывается исключение
- но - помимо этого - есть вот такая разница ...
- пока наш assertThat возвращает void - нас это может не сильно тревожить )
- достаточно - в описании параметров убрать уточнение типа - не ExpectedCondition<Boolean>, а ExpectedCondition
- и assertThat - будет работать с любым из кондишенов
- правда - ничего нам не вернет)
- а вот если хочется получить результат new WebDriverWait(...).until( -
- да еще и не городить кучу методов - придется подумать и немного теории почитать
- */
- /*
- Давай разберемся. Сначала "идейно".
- Этот метод until возвращает такую интересную динамическую штуку-аватар...
- "воплощение" которого зависит от того что именно ты передашь вейт антилу параметром
- - точнее - какой именно кондишен ты ему передаешь...
- А кондишены бывают "разные"... "Разность" эта определеятся "параметром типа" который в джава записывается
- ИмяТипа<ЗДЕСЬ>
- Ты уже ведь использовал списки, например...
- В частности - List<WebElement>
- вот в такой записи типа - его параметром, выступает WebElement, указывая джаве,
- что это не просто список, а "список ВебЕлементов"
- а мог бы быть и списком стрингов например - List<String> или еще чего :)
- Такие "умные" типы которые получают параметр (или несколько параметров) - так и называются - параметризированными
- (а фича языка, в которой они поддерживаются называется - параметрическим полиформизмом -
- не путать с тем другим полиморфмизом... который называется - subtyping polymorphism,
- а в джава все его знают как просто "полиморфизм")...
- Еще они называются - шаблоны... или дженерики...
- Именно так - Java Generics - их принято называть в Java
- Так вот... таким же дженериком является тип ExpectedCondition
- который может быть параметризирован...
- Ты уже встречал запись типа:
- ExpectedCondition<Boolean>
- что же значит этот булеан? что он параметризирует?
- А он параметризирует внутреннюю реализацию этого кондишена...
- Он определяет то, каким должен быть тип возвращаемого значения в методе apply
- То есть...
- Если ты поставишь цель создать кондишен ExpectedCondition<Boolean> - ты должен будешь реализовать
- его метод apply - как возвращающий тип Boolean
- Но зачем вообще нам париться о типе возвращаемой сущности метода apply?
- А потому, что есть еще один "умный дженерик"...
- Только который не "параметризированный класс", а "параметризированный метод"
- (в джава бывают как Generic Types так и Generic Methods)
- и этот параметризированный метод - как раз и есть наш wait.until
- особенность реализации этого метода в том... что он вызывает внутри метод apply
- нашего кондишена... и запоминает то значение, которое этот метод apply возвращает...
- И потом... в конце всей истории... этот метод until - либо бросит исключение
- (в случае если "не дождется" кондишена)
- либо вернет то, что вернул метод apply в "случае успеха"...
- Получается... Если ты передашь вейт антилу кондишен параметризированный типом Boolean
- то в случае успеха антил - вернет тру...
- то есть ты можешь писать код вида:
- if (wait.until(enabled(composeButton))) {
- doSomething();
- }
- но на самом деле, такое нужно не часто...
- то есть - такие кондишены - которые
- параметризированы типом булеан...
- бошьше толку как раз от кондишенов параметризированных типом "того, характеристики чего ждет кондишен"...
- вот кондишен visibilityOf - как раз параметризирован типом WebElement
- ExpectedCondition<WebElement>
- и его метод apply возвращает обьект типа WebElement,
- а "идейно" - возвращает этот же элемент, визибилити которого мы дожидались...
- (если бы мы не дождались - apply вернул бы null - что в этом случае играет роль "false")
- а until в конце концов вернет то, что вернет apply
- и именно поэтому мы можем писать такой код:
- wait.until(visibilityOf(composeButton)).click()
- теперь твоим заданием будет - переделать assertThat что бы он возвращал то что возвращает wait.until
- ну и потом - переделать все свои кондишены, что бы они были параметризированы типом той сущности,
- характеристики которой они должни дожидаться (кстати так выражатся немного некорректно - ведь кондишен не ждет,
- он только выдает информацию - да/нет - а ждет уже вейт антил, ну то такое:) )
- для того, чтобы "правильно реализовать этот wait.until" -
- тебе придется разобраться с этими дженериками...
- И с дженерик типами и дженерик методами.
- И даже этого будет мало...
- Придется покопаться в коде селениума, чтобы понять, что там за тип реально получает
- вейт антил как кондишен...
- Потому что он получает не ExpectedCondition а что то еще более странное...
- Это работает - потому что это "странное" - есть родительским классом для ExpectedCondition
- */
- /*
- Что почитать про Generics
- про дженерики в общем(русский)
- http://www.quizful.net/post/java-generics-tutorial
- http://www.tutorialspoint.com/java/java_generics.htm
- http://developer.alexanderklimov.ru/android/java/generic.php
- конвеншенcы http://stackoverflow.com/questions/2900881/generic-type-parameter-naming-convention-for-java-with-multiple-chars
- https://docs.oracle.com/javase/tutorial/java/generics/types.html
- уроки
- http://docs.oracle.com/javase/tutorial/extra/generics/index.html
- очень приличный faq (есть pdf, и есть кое-что еще, помимо дженериков)
- http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html
- ----------------------------------------------------------
- для понимания кетчера (Catcher)
- http://grepcode.com/file/repo1.maven.org/maven2/com.google.guava/guava/r06/com/google/common/base/Function.java
- http://www.programcreek.com/java-api-examples/com.google.common.base.Function
- https://docs.oracle.com/javase/tutorial/java/generics/lowerBounded.html
- http://stackoverflow.com/questions/3847162/java-generics-super-keyword
- http://stackoverflow.com/questions/2800369/bounding-generics-with-super-keyword
- http://stackoverflow.com/questions/1910892/what-is-the-difference-between-super-and-extends-in-java-generics
- если осилишь после этого и применение кетчера(то, что в прошлом ревью отложили) - можно уже сейчас
- по-прежнему - кетчера можно отложить
- */
Advertisement
Add Comment
Please, Sign In to add comment