Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- src/test/java/framework/
- /*
- все же framework - слишком громкое название)
- давай по сути
- все универсальное - будет находиться в ветке проекта src \ main \ java\...\core
- пейджи - это тоже универсальное - будут в ветке src \ main \ java\...\pages
- тест-классы, тестовые данные, предки тест-класса - в ветке src \ test \ java \ ...
- в самом конце ревью - будут кусочки на почитать
- про структуру проекта - тоже добавлю
- */
- **********************************************
- public abstract class ConsiceAPI {
- /*
- ага, ты добрался до такой версии)
- ок)
- упрощать - не будем)
- класс - универсальный
- см выше - думай - где верно расположить в проекте
- */
- public abstract WebDriver getWebDriver();
- public <V> V assertThat(Function<? super WebDriver,V>condition) {
- return (new WebDriverWait(getWebDriver(), 4)).until(condition);
- }
- /*
- реализовал - верно
- можно чуть упростить параметр
- вместо
- Function<? super WebDriver,V>condition
- использовать
- ExpectedCondition<V> condition
- такое упрощение допустимо
- т к ExpectedCondition<V> - это потомок вот этого типа Function<? super WebDriver,V>
- (new WebDriverWait(...).until - ждет параметра типа Function<? super WebDriver,V>
- и технически - будет все ок
- если вместо значения типа предка - Function<? super WebDriver,V>
- мы передадим значение типа потомка - ExpectedCondition<V>
- а мы только кондишены и намерены передавать
- получим - код, который нам понимать полегче
- уже неплохо)
- что касается таймаута
- тут, в методе, он явно указан равным 4 секунды
- но - ведь нам далеко не всегда таймаут в 4 секунды нужен
- для удобства - реализуй метод с вторым параметром - таймаутом - int timeout
- так - мы при вызове метода assertThat сможем диктовать - какой таймаут нам нужен
- с другой стороны - не удобно каждый раз указывать таймаут
- особенно - если во всех проверках теста нужен какой-то одинаковый таймаут
- потому - реализуй второй метод assertThat
- уже с одним параметром - кондишеном
- в котором переиспользуй ранее реализованный
- а в качестве параметра - укажи значение Configuration.timeout
- в том же пекедже, рядом с ConciseAPI реализуй класс Configuration
- там будем хранить всякие настройки
- пока там будет только таймаут timeout - статическое публичое поле
- по умолчанию равное 4 секундам
- тогда - если нам в тесте нужно будет использовать в проверках таймаут = 15 секундам
- мы в тест-классе (вспомни код задания про GMail на Selenide) укажем таймаут нужных нам размеров
- лишь единожды изменив значение Configuration.timeout
- а assertThat с двумя параметрами - будем использовать только в случаях
- когда для конкретной проверки нужен такой-то таймаут
- идем дальше)
- надеюсь, ты разобрался - что сие значит <V> - в сигнатуре єтого метода
- тоже - ниже ревью - приведу кусочки на почитать
- */
- ************************
- public By byCss(String cssSelector) {
- return By.cssSelector(cssSelector);
- }
- public By by(String cssSelector) {
- return byCss(cssSelector);
- }
- /*
- отличный метод byCss
- думаю, его достаточно
- можно вполне обойтись без метода by
- */
- *************************************************
- public class BaseTest extends ConsiceAPI {
- WebDriver driver = new FirefoxDriver();
- @After
- public void tearDown() {
- driver.quit();
- }
- public WebDriver getWebDriver() {
- return driver;
- }
- }
- /*
- ну... можно и так
- только ты учти
- в таком варианте - перед стартом каждого теста будет создаваться вебдрайвер
- и после каждого теста - удаляться
- если несколько тестов одного тест-класса выполняются в одном потоке - то достаточно
- единожды перед запуском всех тестов - создать вебдрайвер
- и удалить его - после того, как все тесты отработают
- надо четко понимать это
- и использовать нужный тебе вариант
- на создание вебдрайвера - тоже уходит время и ресурсы
- потому - тут надо отталкиваться от поставленой задачи
- проверь - как пишется слово concise
- concise vs consice
- */
- ************************************************
- public class BasePage extends ConsiceAPI {
- /*
- к предку пейджей BasePage - вопросов нет
- это - универсальный класс
- расположи правильно (выше писала - что где)
- */
- ***********************************************
- public class GooglePage extends BasePage {
- ...
- public void followFirstResult(){
- $(firstResult).findElement(by(".r a")).click();
- }
- }
- /*
- ну, уже отладился - как использовать $(...)
- это ок
- теперь - переходим к реализации нашей задачи - gMail
- оттолкнись от своей же селенидовской версии
- первое
- перенеси в этот проект пейджи (см ревью выше - где их правильно расположить)
- пейджи отнаследуй от BasePage
- пейджи мы будем использовать в режиме пейджей-объектов -
- потому подправь имена классов пейджей и объявления полей и методов
- (имена классов пейджей-объектов - заканчиваются на Page, поля и методы - не статические)
- метод $(...) - уже рабочий, и это ок
- проверки assertMail & assertMails, и саму переменую mails - пока закомментируй
- это сделаем позже
- сначала - реализуем все методы-действия
- тебе не хватит методов
- byText
- и
- byTitle
- посмотри - как они реализованы в селениде
- фактически - вызывается By.xPath(...) с правильным аргументом
- какой это - правильный аргумент - можно как раз в Selenide подсмотреть
- ну или самостоятельно написать xPath-выражение
- что использовать
- вместо - setValue(text) или pressEnter() для вебэлемента -
- думаю, догадаешься
- предыдущие работы по селениуму в помощь
- второе
- перенеси класс с тестовыми данными и тест-класс
- правильно изх расположи
- тест-класс - отнаследуй от BaseTest
- правильно инициализируй пейджи
- в GoogleTest - пример есть
- настрой Configuration.timeout (в селенидовской версии - пример есть)
- реализуй весь сценарий (за исключением проверок)
- цель - получить работающий сценарий -
- залогинились, отправили письмо, обновили, перешли в отправленные,
- вернулись во входящие, поискали
- проверки - пока закомментируй
- цель номер один - получить вот это
- !!! - зафиксируй в репозитории версию
- !!! если это окажется не сложным - продолжай
- определись - какую первую версию ты хочешь делать
- это - последняя работа
- где еще можно применить @FindBy элементы
- потому - советую с ними потренироваться
- потому в пейдже
- заведи @FindBy переменную для списка мейлов (селектор ты знаешь - см селенидовскую работу)
- и пришла пора реализовывать проверки)
- будем проверять список мейлов
- нам нужны новых 2 кондишена для проверки списка мейлов
- в assertMail - assertThat(nthElementHasText(mails, 0, mailText))
- в assertMails - assertThat(textsOf(mails, mailTexts))
- nthElementHasText -
- получить элемент с индексом ...
- и текст этого элемента
- проверь текст этого элемента на соответствие переданному
- textsOf
- получить тексты всех элементов
- сверить количество текстов фактических и переданных в кондишен (ожидаемых)
- если количество не равно - проверка не прошла
- если количество равно - сверяешь попарно тексты - нулевой фактический с нулевым ожидаемым,
- первый - с первым и т д
- если тексты соответствуют - продолжаем проверять
- если не соответствуют - уже проверка не прошла
- если все тексты соответствуют - проверка прошла
- логику обоих кондишенов кратко я описала
- открой селениумский модуль ExpectedConditions (напиши в коде ExpectedConditions и, зажав ctrl, кликни)
- и посмотри - как устроены стандартные селениумские кондишены
- посмотри предыдущие задания - повспоминай - как ты писал кондишены попроще
- по идее - на этом этапе - точно должны появиться вопросы)
- постарайся - получить список максимально конкретных вопросов
- в любом случае, разберем - любые
- но - пока будешь писать эти вопросы - многое сам поймешь и разберешь)
- вопросы собирай в отдельый список
- потом списком же - и отдашь мне
- хоть в pastebin выложи
- хоть код комментируй - вопросы пиши
- хоть - планируй голосовое общение
- все варианты годятся
- */
- *************************************************
- ***************на почитать***********************
- *************************************************
- /*
- http://joxi.ru/nAyqEx7HXvxQoA
- вот пример хорошей структуры проекта
- в src \ main
- core - универсальное, что можно переиспользовать в разных проектах
- pages - пейджи тоже можно переиспользовать для других тестов этого же приложения
- в src \ test
- testdata - тестовые данные (если такие есть и они вынесены в отдельный класс)
- testconfigs - предки тест-класса (так можно их изолировать от собственно тест-классов - чтоб легче было ориентироваться
- про пекеджи еще немного)
- если GroupID = com.somesite
- а проект todomvctest
- то пакет корневой должен быть com.somesite.todomvctest
- логика - чтобы "не смешивались имена сущностей"
- внутри одной компании - может быть несколько проектов)
- и у всех у них один com.somesite - базовый пекедж
- но для каждого проекта должен быть свой “базовый пекедж проекта"
- иначе все смешается)
- важно то, что когда этот проект выльется в отдельную библиотеку,
- то не будет конфликтов при его подключении
- */
- ********************
- /*
- Кодишенов есть много и разных
- и далеко не все они 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( -
- да еще и не городить кучу методов - придется подумать и немного теории почитать
- */
- *******
- /*
- assertThat(visibilityOf(composeButton), driver);
- composeButton.click();
- код такого типа можно записать в одну строку
- типа вот так:
- assertThat(visibilityOf(composeButton), driver).click();
- точнее... можно было бы... если бы ты "правильно обернула метода wait.until" внутрь assertThat
- то есть, оригинальный код:
- wait.until(visibilityOf(composeButton)).click()
- будет работать. Тебе просто нужно сделать так, что бы assertThat возвращал не void а то же что возвращает wait.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()
- лучше реализовывать все свои кондишены, чтобы они были параметризированы типом той сущности,
- характеристики, которой они должни дожидаться
- (кстати, так выражатся немного некорректно - ведь кондишен не ждет,
- он только выдает информацию - да/нет - а ждет уже вейт антил, ну то такое:) )
- для того что бы "правильно реализовать этот wait.until" - тебе придется разобраться с этими дженериками...
- И с дженерик типами и дженерик методами.
- */
- *****
- /*
- про дженерики в общем(русский)
- 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
- */
Advertisement
Add Comment
Please, Sign In to add comment