Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- public <V> V assertThat(ExpectedCondition<V> condition) {
- return (new WebDriverWait(getWebDriver(), 20)).until(condition);
- }
- /*
- тут - уже почти ок)
- надо добавить немного гибкости
- ведь не всегда таймаут именно такого размера требуется
- если
- реализовать assertThat со вторым параметром - таймаутом
- то
- можно будет при вызове проверки - явно указывать размер таймаута
- это бывает удобно - когда в проекте есть проверки, требующие какого-то не стандартного таймаута
- в то же время
- для всех проверок указывать аймаут - уже перебор)
- потому - реализуем второй assertThat - уже без параметра - таймута
- в нем - вызовем первый assertThat и в качестве таймаута укажем значение Configuration.timeout
- Тут же, в core, реализуем класс Configuration со статическим полем timeout,
- в котором будет задан таймаут по умолчанию (разумно его установить равным 4 секунды)
- А если для тестов значения по умолчанию Configuration.timeout недостаточно
- то всегда есть возможность в тест-классе настроить самостоятельно Configuration.timeout
- Собственно - мы аналогично поступали - когда реализовывали версию этого задания на Selenide
- мы для этого теста изменяли значение Configuration.timeout
- */
- *********************************
- public abstract class ConsizeAPI {
- /*
- Con__c__i__s___e
- 2 буквы поправь)
- ошибки спеллинга IntelIJ Idea подчеркивает зеленой волнистой линией - обрати внимание
- */
- **************************************
- public static ExpectedCondition<Boolean> text(final int index, final By elementLocator, final String expectedText) {
- /*
- для этого кондишена лучше чуть подробнее имя использовть
- listNthElementHasText - к примеру
- этот кондишен можно было бы реализовать как
- ExpectedCondition<WebElement>
- или
- ExpectedCondition<List<WebElement>>
- при работе apply этого или других кондишенов - могут возникать исключения
- в частности - в этом кондишене - может возникнуть
- IndexOutOfBoundsException
- при пролучении элемента списка за его границами
- почитай вот это
- https://docs.google.com/document/d/1BiYTLdypDfucSqiY9isv1HCKKQIxelzqYrN-3Ku1RWM/edit?usp=sharing
- это - метод, который позволит не использовать в каждом из кондишенов try-catch секции
- общее замечание - у кетчера можно будет
- вместо параметра final Function<? super WebDriver, V> condition
- использовать более простой для понимания ExpectedCondition<V>
- Function<? super WebDriver, V> - это предок для ExpectedCondition<V>
- и значение такого типа - принимает until (WebDriverWait)
- ниже - приведу информацию - чтобы получше разобраться с таким решением
- */
- ********************
- public static ExpectedCondition<Boolean> text(final int index, final By elementLocator, final String expectedText) {
- ....
- public String toString() {
- return String.format("\n %s -th element in locator %s\n should have text: %s\n while actual text is: %s\n",
- index, elementLocator, expectedText, actualTexts.get(index));
- }
- /*
- не надо в toString() выводить actualTexts.get(index)
- не факт - что такой элемент есть в списке
- может возникнуть исключение IndexOutOfBoundsException и
- сообщение об ошибке будет скомканным
- тут - раз уж у тебя есть все фактические тексты списка элементов - полезнее вывести
- список целиком actualTexts
- */
- ******************************
- actualTexts = new ArrayList<String>();
- for (WebElement element : elements) {
- actualTexts.add(element.getText());
- }
- /*
- Этот код используется в 2-ух кондишенах
- реализуй метод List<String> getTexts(List<WebElements>)
- и примени его тут
- сам метод - размести в классе-контейнере универсальіх статических методов Helpers
- */
- *********************************
- public class BasePage extends ConsizeAPI
- /*
- BasePage - реализован верно
- размести его в core
- т к у него - универсальная функциональность
- реформатируй код - выравнивание отличается от стандартного
- */
- ************************************
- public class BaseTest extends ConsizeAPI {
- WebDriver driver = new FirefoxDriver();
- @Before
- public void driverOpen() {
- driver.get("http://gmail.com/");
- }
- @After
- public void driverQuit() {
- driver.quit();
- }
- /*
- ну да, можно и так
- важно - чтоб ты понимала - когда какой вариант тебе нужен
- в варианте
- создание вебдрайвера
- инициализация не статического поля
- или
- instance initialization block
- или
- @Before-метод
- удаление вебдрайвера
- @After-метод
- все ОК
- перед каждым тестом - делаем новый вебдрайвер
- после каждого теста - удаляем его
- есть еще рабочий вариант
- создание вебдрайвера
- инициализация статического поля
- или
- static initialization block
- или
- @BeforeClass-метод
- удаление вебдрайвера
- @AfterClass-метод
- все ОК
- перед запуском всех тестов класса (единожды) - делаем новый вебдрайвер
- после выполнения всех тестов класса (единожды) - удаляем его
- важно - чтобы создание-удаление вебдрайвера выполнялось соотвественно друг другу
- описанные выше варианты - ок
- а если создавать вебдрайвер перед каждым тестом в @Before-методе,
- а удалять - после выполнения всех тестов @AfterClass-методе
- то получится - ерунда
- будут оставаться открытые браузеры
- а вот какой из рабочих вариантов выбрать - надо исходить из текущих задач
- если тесты одного класса не выполняются в параллельном режиме - то достаточно
- единожды создать и удалить вебдрайвер - на все тесты этого класса
- при параллельном запуске - конечно, на каждый тест будет нужен свой вебдрайвер
- так что - тут бы я все же использовала @BeforeClass + @AfterClass
- так поэкономнее)
- хотя - пока у нас единственный тест-метод - по большому счету - разницы мы не увидим
- просто - про такие вещи лучше сразу думать
- можешь оставить как есть, можешь переделать на вариант с @BeforeClass + @AfterClass
- важно - чтоб было понимание
- */
- **************************************************************************
- /*
- дальше - кусочки, шире раскрывающие тему
- для понимания, а не для выполнения
- почитай, поразбирайся
- */
- /*
- instance initialization block - будет выполняться перед запуском каждого тест-метода
- static initialization block - перед запуском всех тест-методов тест-класса
- http://www.javamadesoeasy.com/2015/06/differences-between-instance.html
- разница по эффекту - как использовать @Before или @BeforeClass метод
- */
- /*
- BeforeClass vs static initialization block
- http://stackoverflow.com/questions/15493189/beforeclass-vs-static
- Получим более содержательное сообщение об ошибке - если работаем с аннотированными методами
- http://www.unknownerror.org/opensource/junit-team/junit/q/stackoverflow/512184/best-practice-initialize-junit-class-fields-in-setup-or-at-declaration
- про ругань красивую - http://www.javaworld.com/article/2076265/testing-debugging/junit-best-practices.html
- (подзаголовок Do not use the test-case constructor to set up a test case)
- */
- ****
- /*
- это по нашему с тобой вчерашнему разговору,
- все то же, что ты уже применила - т е ДЕЛАТЬ НИЧЕГО НЕ НАДО )
- ты уже это сделала )
- возможно - полезно будет почитать
- */
- /*
- Кодишенов есть много и разных
- и далеко не все они 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( -
- да еще и не городить кучу методов - придется подумать и немного теории почитать
- */
- public static WebElement $(WebDriver driver, By elementLocator) {
- assertThat(driver, visibilityOfElementLocated(elementLocator));
- return driver.findElement(elementLocator);
- }
- /*
- вот этот кондишен visibilityOfElementLocated - типа ExpectedCondition<WebElement>
- значит - если бы assertThat возвращал то же, что и new WebDriverWait(...).until(...)
- то - assertThat вернул бы вебэлемент
- и нам не пришлось бы его искать дополнительно
- и метод выглядел бы вот так
- */
- public static WebElement $(WebDriver driver, By elementLocator) {
- return assertThat(driver, visibilityOfElementLocated(elementLocator));
- }
- /*
- Это не единственный вариант, когда нам это может пригодиться
- но для самого простого и полезного примера - самое то)
- теперь - как этого добиться
- */
- /*
- Давай разберемся. Сначала "идейно".
- Этот метод 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