Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- http://joxi.ru/DrlQ5oLh4WnbMm
- /*
- заботься о форматировании кода
- пропуск одной строки - разумно использовать для форматирования
- а пропуск нескольких строк к ряду - уже лишнее
- https://google.github.io/styleguide/javaguide.html#s4.6.1-vertical-whitespace
- пропуск строки снутри методов используешь по-разному
- иногда - первую строку пропускаешь
- иногда - нет
- я бы придерживалась какого-то одного правила
- например, если метод одно-двустрочный - не делать пропусков строк внутри метода
- а если код в методе надо делить по блокам для более простого понимания
- то и вначале и в конце метода я бы тоже строку пропустила
- отступы отлчаются от стандартных
- выдели код
- и с меню code->reformat code
- такие действия - стоит делать привычкой
- перед тем, как отдаешь код кому-то или выкладываешь в репозиторий
- они простые, не требуют раздумий особых
- а код от этого выглядит нагляднее
- */
- ****************************************
- public abstract class ConciseApi {
- /*
- класс нужно объявлять абстрактным - если ты планируешь от него что-то наследовать
- и если внутри методов класса ты хочешь оперировать методом, который реализуешь в потомках
- вот такой метод - который у потомков будет по-разному реализован, и который уже на уровне предка
- используется в логике других методов - объявляется в классе-предка как абстрактный класс
- в данной версии - этого нету
- ConciseApi - просто класс-контейнер статических методов, полезных нам и в пейджах, и в тест-классах
- В следующей версии как раз будет версия, когда ConciseApi будет абстрактным предком для других классов
- конечно, можно объявлять класс абстрактным только для того, чтобы показать,
- что объекты такого класса не могут создаваться.
- по моему мнению, в таком случае можно это не уточнять
- раз в классе - все методы статические, я уже понимаю - для чего этот класс
- это класс - контейнер статических методов, и объект такого типа я точно делать не буду
- конечно, уточнив, что класс - abstract, создать объект такого типа станет просто невозможным)
- если есть причины об это обеспечить - наверное надо объявлять класс как abstract
- вспомни - мы пейджи-модули, или классы-хелперы - не объявляли ведь как abstract
- хотя и подразумевали - что объектов такого класса создавать не будем
- почитать про абстрактные классы
- тут немного сложновато для начала
- http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html
- тут примеры простого кода
- http://www.javatpoint.com/abstract-class-in-java
- тоже неплохо - пример и объяснения
- http://tutorials.jenkov.com/java/abstract-classes.html
- пример и пошаговые объяснения
- http://crunchify.com/what-is-an-abstract-class-and-abstract-method-in-java-when-should-i-use-it/
- теория с примерами
- https://www.tutorialspoint.com/java/java_abstraction.htm
- вопрос и ответы, сложновато, но вопрос рассматривается с разных сторон
- http://stackoverflow.com/questions/1320745/abstract-class-in-java
- */
- ************************
- http://joxi.ru/v29WjP9hG0QQbr
- /*
- а вот кондишену - не нужен параметр - вебдрайвер
- 1 - параметр не нужен
- 2 - т к у метода apply кондишена уже есть такой параметр, нам его будет достаточно
- */
- ****************************************
- public static ExpectedCondition<Boolean> nthElementHasText(WebDriver driver, final By elementsLocator, final int index, final String text) {
- return new ExpectedCondition<Boolean>() {
- private List<WebElement> elements;
- /*
- лучше на уровне класса объявлять те переменные, которые нам пригодятся в нескольких методах
- ты, в общем, так и сделала)
- я предлагаю на уровне toString -
- оперировать либо списком строк - фактических текстов элементов вписка
- либо строкой - фактическим текстом index-ого элемента списка
- и уже не писать ничего про размер списка и прочие вещи
- в таком случае - на этом уровне нужны переменные либо
- List<String> actualTexts
- или
- String actualText
- в apply - нужно заполнить такую переменную
- и для простоты понимания - и анализировать ее значение
- а в toString() - использовать значение такой переменной для построения сообщения
- а List<WebElement> elements - объявлять и использовать только внутри apply
- */
- @Override
- public Boolean apply(WebDriver driver) {
- elements = driver.findElements(elementsLocator);
- if (index < elements.size()) {
- return elements.get(index).getText().contains(text);
- } else
- return false;
- /*
- обрати внимание - в if-блоке используешь фигурные скобки,
- а в else-блоке - не используешь
- согласно conventions - надо использовать даже если у тебя одна строка кода
- https://google.github.io/styleguide/javaguide.html#s4.1.1-braces-always-used
- но не спеши подправлять код)
- предлагаю его переписать)
- на самом деле - проверяя index < elements.size()
- ты пыталась избежать IndexOfBoundsException
- которое возникает, когда мы пытаемся обратиться к элементу коллекции по индексу за ее границами
- можно поступить по-другому
- try{
- actualText = elements.get(index).getText();
- return actualText.contains(text);
- } catch (IndexOutOfBoundsException e) {
- return false;
- }
- на самом деле, в процессе работы метода apply могут возникать и другие исключения
- и их тоже нужно ловить и обрабатывать
- почитай
- https://docs.google.com/document/d/1BiYTLdypDfucSqiY9isv1HCKKQIxelzqYrN-3Ku1RWM/edit?usp=sharing
- и примени такое решение
- можно чуть упростить тип параметра этого кетчера
- вместо
- Function<? super WebDriver, V> condition
- применять
- ExpectedCondition<V> condition
- т к Function<? super WebDriver, V> - это предок для ExpectedCondition<V> condition
- туда же, в кетчер, можно перенести и работу с IndexOutOfBoundsException
- и тогда все кондишены будут без try-catch секций - что проще
- а логика перехвата исключений - будет отделена в кетчер
- это позволит при разработке самих кондишенов сосредоточиться на главном - логике проверки
- да и читать такой код будет проще
- */
- }
- @Override
- public String toString() {
- if (index < elements.size()) {
- return String.format("\n element with index %s to be: %s, while actual value is: %s", index, text, elements.get(index));
- } else {
- return String.format("\n index is: %s, while actual size of elements is: %s", index, elements.size());
- }
- }
- /*
- тут, и в других кондишенах строй фразу по некой одной схеме
- в toString уже не должно быть накакой логики или получения чего-то из элементов заново
- тут - оперируем тем, что анализировали в apply
- element foynd by locator ....
- should contain text ....
- while actual text is ... (или - while actual texts are ... - если мы собирали список текстов)
- */
- };
- }
- **********************************
- http://joxi.ru/DmBNWL6FNVP1Nm
- /*
- вспомни из видео - как работает new WebDriverWait(...).until(...)
- apply кондишена вызывается в цикле - пока не закончится таймаут или проверка не пройдет
- потому нам важно именно ВНУТРИ apply - заново получать список элементов
- так, как реализовано сейчас - мы не переискиваем список
- и получается - что многократные вызовы apply все равно будут работать с вариантом списка
- который мы получили изначально - а в этом смысла нету
- как и ранее писала - советую в apply собрать список текстов элементов
- и затем его анализировать
- и в toString - именно его и вывести как часть выражения
- */
- *****************************************
- public static ExpectedCondition<Boolean> elementsHaveText(final WebDriver driver, final By elementsLocator, final String... texts) {
- /*
- разумнее объявить этот кондишен как ExpectedCondition<List<WebElement>>
- да, мы это в коде не используем
- но потенциально - это полезнее
- т к в таком случае assertThat для кондишена вернет список вебэлементов
- и это может быть полезно
- подумай над типами других уже реализованных кондишенов
- про имя кондишена
- можно назвать по аналогии с sizeOf - textsOf
- */
- ....
- @Override
- public String toString() {
- if (elements.size() != texts.length) {
- return String.format("\n total elements value %s, does not match texts value: %s", elements.size(), texts.length);
- } else {
- return String.format("\n elements text to be: %s, while actual are %s", texts, elements);
- }
- }
- /*
- тут, и далее - используй тот же принцип - выше писала
- никакой логики дополнительной не должно быть
- никаких новых получений данных
- выводим только то, что анализировали
- elements of list found by locator ...
- should contain texts ....
- while actual texts are ....
- */
- **************************
- public class Mails {
- private static By elementsLocator = By.cssSelector("[role ='main'] .zA");
- /*
- эту переменную стоит назвать в терминах нашего пейджа
- mails - будет ок
- а то, что это именно локатор - будет понятно по типу переменной
- */
- ***************************
- @Step
- public void assertMail(int index, String mailTitleText) {
- assertThat(driver, CustomConditions.nthElementHasText(driver, elementsLocator, index, mailTitleText));
- }
- /*
- используй import static для CustomConditions.nthElementHasText
- и тогда в коде сможешь использовать nthElementHasText
- касается использования любых кондишенов
- как использовать import static - до некоторой степени субъективно)
- я придерживаюсь такого принципа
- если слово слишком распространенное и/или контекст вызова не помогает это понять -
- то уточняю до имени класса
- или - если решили все статические методы этого класса вызывать указывая имя класса
- (как мы про пейджи решили для Gmail)
- иначе - использую import static
- так - например -
- в селениде проектах - использовав кондишены empty / visible - мы использовали import static и не уточнялись
- до имени класса - т к и так все понятно из контекста
- несмотря на то - что сами термины empty / visible используются в разных классах -
- мы могли себе позволить не уточняться до класса - т к контекст вызова все объяснял
- а вот By.name(...), String.join(... - я бы уточнялась до класса - т к по одному имени метода непонятно -
- что за зверь
- и тот, кто код читает - будет вынужден посмотреть - что мы там наимпортили
- */
- *************************
- public class BaseTest {
- protected static WebDriver driver;
- @BeforeClass
- public static void setup() {
- Configuration.timeout = 6;
- driver = new ChromeDriver();
- }
- @AfterClass
- public static void tearDown() {
- driver.quit();
- }
- }
- /*
- реализация предка для тест-класса - ок
- реализован он почти универсально
- почти - т к установка таймаута портит уиверсальный код
- Configuration.timeout = 6; - это уже логика самого тест-класса, а не его предка
- советую перенести это в тест-класс
- вспомни - мы для Gmail - когда реализовывали это задание в Selenide - устанавливали таймаут в 15 секунд
- мне вообще приходится устанавливать в 20 )
- возможно - и тебе таймаута не хватает
- */
- ************************
- public class GmailTest extends BaseTest {
- @Test
- public void testLoginSendAndSearch() {
- String subject = generateUniqueString("test");
- Gmail gmail = new Gmail(driver);
- Mails mails = new Mails(driver);
- Menu menu = new Menu(driver);
- /*
- пейджи - лучше обїявляй не в тест-методе
- а на уровне тест-класса
- понятно, что в данном случае у нас один тест-метод и технически - без разницы -
- где объявлять пейджи
- но - технически -
- в тест-классе - может быть сколь угодно много тест-методов
- и они могут появляться постепенно
- вот появится второй тест-метод у нас тут
- и нам из-за этого придется менять старый тест-метод
- не очень логично)
- а самое главное - все же пейдж = набор инструментов, нужный для конкретного тест-класса
- это именно "собственность"/ответственность/логика тест-класса, а не тест-метода
- потому правильнее пейджи объявлять и инициализировать на уровне тест-класса, а не тест-метода
- */
Advertisement
Add Comment
Please, Sign In to add comment