julia_v_iluhina

Untitled

Sep 28th, 2016
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 19.08 KB | None | 0 0
  1. /*
  2.     очень эффективно применил знания из предыдущих селениумских заданий)
  3.     это ты молодец)
  4.  
  5.     будем улучшать)
  6.  
  7.     еще надо принять решение - будешь ти ты при улучшении реализации этого задания работать
  8.     с элементами аннотированными @FindBy
  9.  
  10.     далее - точно уже с этим работать не будем
  11.     из этих соображений - стоило бы познакомиться с ними поближе)
  12.     т к может пригодиться на приктике - стоит понимать как с ними работать
  13.  
  14.     но на самом деле - их использование мало что дает...
  15.  
  16.     так что - на твой выбор)
  17. */
  18. *********************************************
  19.  
  20. public class GMailTest {
  21.     public static WebDriver driver = new FirefoxDriver();
  22. /*
  23.     драйвер создал - это ок
  24.     в селениуме - надо самостоятельно заботиться о его закрытии
  25.  
  26.     раз ты driver объявил статической переменной - то инициализация переменной произойдет перед
  27.     запуском всех тест-методов класса
  28.  
  29.     значит - закрывать вебдрайвер надо в методе  @AfterClass
  30.  
  31.     а что вызвать для вебдрайвера - close vs quit - почитай)
  32.         http://stackoverflow.com/questions/15067107/difference-between-webdriver-dispose-close-and-quit
  33.         http://www.testingdiaries.com/driver-close-and-driver-quit/
  34.         http://internetka.in.ua/selenium-webdriver-quit-or-close/
  35.  
  36.     вот эта функциональность - драйвер, его создание и удаление - нужна в любом тест-классе
  37.     и ее стоит вынести в предка тест-класса
  38.     чтобы это можно было переиспользовать
  39.  
  40. */
  41.  
  42. /*
  43.     на самом деле - у нас есть варианты - когда создавать и вогда закрывать вебдрайвер
  44.     выше предложенный вариант - тут самый оптимальный
  45.     тут - опишу - что мы вообще можем, и как лучше
  46.  
  47.     чтоб не путаться, всегда при проектировании придерживайся принципов
  48.             метод создающий и метод удаляющий - располагай в одном классе
  49.  
  50.             позаботься о соотвествующих друг другу способах вызова таких методов
  51.                 если создали в  BeforeClass, то убили в  AfterClass
  52.                     (это вариант = создали перед запуском всех тест-методов класса и убили после того,
  53.                     как все тесты отработали)
  54.                         вызов BeforeClass можно заменить на инициализацию статического поля или
  55.                         static initialization block
  56.  
  57.                 если создали в  Before, то убили в  After
  58.                     (это вариант - перед запуском каждого тест-методы создали,
  59.                     после того как тест-метод отработал - убили
  60.                     такой вариант хорош для запусков тест-методов в параллельных потоках, это потом будет)
  61.                         вызов  Before можно заменить на инициализацию НЕ статического поля или
  62.                         instance initialization block
  63.             про это - ниже чуть подробнее распишу
  64.  
  65.     полезные линки для бОльшего углубления понимания
  66.         http://stackoverflow.com/questions/15493189/beforeclass-vs-static
  67.  
  68.         http://www.unknownerror.org/opensource/junit-team/junit/q/stackoverflow/512184/best-practice-initialize-junit-class-fields-in-setup-or-at-declaration
  69.  
  70.         http://www.javaworld.com/article/2076265/testing-debugging/junit-best-practices.html
  71.         (подзаголовок Do not use the test-case constructor to set up a test case)
  72.  
  73. */
  74. ********************************************
  75.     @Test
  76.     public void basicEmailLifeCycle() {
  77. /*
  78.     к реализации самого тест-метода - вопросо нет)
  79.     будем разбираться со вспомогательными методами
  80. */
  81. ******************************************************
  82.     public WebElement $(By searchByText){
  83.         return new WebDriverWait(driver, Configuration.timeout).until(visibilityOfElementLocated(searchByText));
  84.     }
  85.  
  86.     public By byText(String seaarchText){
  87.         return By.xpath(".//*[text() = \"" + seaarchText + "\"]");
  88.     }
  89. /*
  90.     эти 2 метода - явно могут пригодиться не только для конкретного тест-класса
  91.     они универсальны )
  92.  
  93.     да, для реализации метода $ - нам нужен вебдрайвер
  94.     пока это решим еще одним дополнительным параметром метода
  95.      у нас будет метод
  96.      не WebElement $(By searchByText)
  97.      а WebElement $(WebDriver driver,  By elementLocator)
  98.  
  99.     обрати внимание на имя второго параметра
  100.     такой метод мы сможем вынести в класс-контейнер универсальных статических методов
  101.     давай его назовем ConciseAPI
  102.     как и все универсальное - его правильно расположить в ветке проекта src \ main
  103.     (там, где сейчас класс Helpers расположен)
  104.  
  105.     как следствие - туда же нужно переместить и класс Configuration
  106.     ну и это просто правильно - т к это тоже универсальная штука )
  107.  
  108.     кстати, правильнее в самом Configuration выставить таймаут в более общепринятое значение
  109.     например, в селениде - это было 4 секунды
  110.     а в самом тест-классе - уже установить бОльший таймаут
  111.     вспомни - как ты это же делал в аналогичном селенидовском проекте
  112.  
  113.     метод By byText(String seaarchText)
  114.     тоже пусть будет методом из ConciseAPI
  115.     только подравняй имя параметра
  116.     речь про текст элемента
  117.     можно text, elementText
  118.  
  119.     также - можно реализовать методы
  120.         byCss - чтоб сократить By.cssSelector
  121.         byTitle / byExactTitle - чтоб упростить
  122.             By.cssSelector("[title='...']")
  123.             By.cssSelector("[title~=...]")
  124.  
  125.         и метод $ с параметром String cssSelector (ну и еще один параметр - вебдрайвер, конечно)
  126.             чтоб вместо $(By.cssSelector("..."))
  127.             использовать $(driver, "...")
  128.  
  129.     примени разработанные методы в коде вспомогательных методов
  130. */
  131. /*
  132.     итог
  133.        логику работы с вебдрайвером - спрятали в предке тест-класса
  134.        вспомогательные универсальные методы - вынесли в отдельный класс ConciseAPI
  135.             минус - в некоторых методах, требующих вебдрайвер, пришлось добавить еще один параметр
  136.             мы этот минус в следующих заданиях уберем
  137.             пока - будем мириться с ним)
  138.  
  139.     уже код упростится
  140.     дальше упрощаем)
  141. */
  142. ******************************************
  143.  
  144.     public void visit(){
  145.         driver.get("http://gmail.com");
  146.     }
  147. /*
  148.     в ConciseAPI реализуй метод open(WebDriver driver, String url)
  149.     и тут его используй
  150. */
  151. ****************************
  152.     public void refresh(){
  153.         $(By.className("asf")).click();
  154.     }
  155. /*
  156.     это можно будет переписать проще - передать методу $
  157.     не By.className("asf")
  158.     а цсс селектор ".asf"
  159. */
  160. **********************************************
  161.     public void assertMail(int  index, String mailHeaderText){
  162.         new WebDriverWait(driver, Configuration.timeout).until(textToBePresentInElementLocated(By.cssSelector("[role='main'] .zA:nth-child(" + index+1 + ")"), mailHeaderText));
  163.     }
  164.  
  165.     public void assertMails(String... mailHeaderText){
  166.         for(String text : mailHeaderText)
  167.             new WebDriverWait(driver, Configuration.timeout).until(textToBePresentInElementLocated(By.cssSelector("[role='main'] .zA"), text));
  168.     }
  169. /*
  170.     ну ... выкрутился)
  171.     и почти что этого хватило)
  172.  
  173.     для assertMails - надо было при такой реализации еще и размер списка проверить)
  174.     но - не торопись это добавлять
  175.  
  176.     мы пойдем немного другим путем
  177.  
  178.     new WebDriverWait(driver, Configuration.timeout).until(...) - такого рода код мы уже и в методе
  179.     $ использовали
  180.    
  181.     давай в ConciseAPI реализуем метод
  182.    
  183.     void assertThat(WebDriver driver, ExpectedCondition condition)
  184.     в котором - собственно и будет вызов
  185.     new WebDriverWait(driver, Configuration.timeout).until(condition)
  186.    
  187.     этот метод можно будет использовать в assertMail и assertMails
  188.    
  189.     но - хотелось бы еще и реализацию метода $ упростить
  190.     там у нас код
  191.     return new WebDriverWait(driver, Configuration.timeout).until(visibilityOfElementLocated(searchByText))
  192.     т е - мы возвращаем то, что возвращает нам until
  193.     а он - возвратить может значения разных типов
  194.     все зависит от того, какой кондишен мы ему передадим
  195.     если ExpectedCondition<WebElement> - то until вернет WebElement
  196.     если ExpectedCondition<Boolean> - то until вернет Boolean
  197.    
  198.     можно конечно реализовать несколько assertThat
  199.     WebElement assertThat(WebDriver driver, ExpectedCondition<WebElement> condition)
  200.     Boolean assertThat(WebDriver driver, ExpectedCondition<Boolean> condition)
  201.    
  202.     но - в Java есть способ поинтереснее )
  203.       Погугли java generic method
  204.             Вот статья на русском, сравнительно понятная
  205.             http://www.quizful.net/post/java-generics-tutorial
  206.    
  207.             Вместо таких нескольких методов можно сделать один такой
  208.    
  209.                 public <V> void assertThat(WebDriver driver, ExpectedCondition<V> condition) {
  210.                     (new WebDriverWait(driver, Configuration.timeout)).until(condition);
  211.                 }
  212.    
  213.             отличия - при объявлении такого метода мы говорим, что пока не знаем какой тип будет использоваться у
  214.             параметра типа ExpectedCondition<...>
  215.    
  216.             это нам даст как раз возможность использовать один метод вместо нескольких -
  217.             у которых в ExpectedCondition<...>
  218.             явно задан тип
  219.    
  220.             и тогда метод  $ тоже упростится          
  221.                 public WebElement $(WebDriver driver, By locator) {
  222.                     return assertThat(driver, visibilityOfElementLocated(locator));
  223.                 }
  224.    
  225.    
  226.      еще - приведу пояснения Якова по этой теме      
  227. */
  228. /*
  229. Давай разберемся. Сначала "идейно".
  230.  
  231. Этот метод until возвращает такую интересную динамическую штуку-аватар...
  232. "воплощение" которого зависит от того что именно ты передашь вейт антилу параметром
  233. - точнее - какой именно кондишен ты ему передаешь...
  234.  
  235. А кондишены бывают "разные"... "Разность" эта определеятся "параметром типа" который в джава записывается
  236. ИмяТипа<ЗДЕСЬ>
  237.  
  238. Ты уже ведь использовал списки, например...
  239. В частности - List<WebElement>
  240.  
  241. вот в такой записи типа - его параметром, выступает WebElement, указывая джаве,
  242. что это не просто список, а "список ВебЕлементов"
  243. а мог бы быть и списком стрингов например - List<String> или еще чего :)
  244.  
  245. Такие "умные" типы которые получают параметр (или несколько параметров) - так и называются - параметризированными
  246. (а фича языка, в которой они поддерживаются называется - параметрическим полиформизмом -
  247. не путать с тем другим полиморфмизом... который называется - subtyping polymorphism,
  248. а в джава все его знают как просто "полиморфизм")...
  249. Еще они называются - шаблоны... или дженерики...
  250. Именно так - Java Generics - их принято называть в Java
  251.  
  252. Так вот... таким же дженериком является тип ExpectedCondition
  253. который может быть параметризирован...
  254.  
  255. Ты уже встречал запись типа:
  256. ExpectedCondition<Boolean>
  257.  
  258. что же значит этот булеан? что он параметризирует?
  259. А он параметризирует внутреннюю реализацию этого кондишена...
  260. Он определяет то, каким должен быть тип возвращаемого значения в методе apply
  261.  
  262. То есть...
  263. Если ты поставишь цель создать кондишен ExpectedCondition<Boolean> - ты должен будешь реализовать
  264. его метод apply -  как возвращающий тип Boolean
  265.  
  266. Но зачем вообще нам париться о типе возвращаемой сущности метода apply?
  267.  
  268. А потому, что есть еще один "умный дженерик"...
  269. Только который не "параметризированный класс", а "параметризированный метод"
  270. (в джава бывают как Generic Types так и Generic Methods)
  271.  
  272. и этот параметризированный метод - как раз и есть наш wait.until
  273.  
  274. особенность реализации этого метода в том... что он вызывает внутри метод apply
  275. нашего кондишена... и запоминает то значение, которое этот метод apply возвращает...
  276.  
  277. И потом... в конце всей истории... этот метод until - либо бросит исключение
  278. (в случае если "не дождется" кондишена)
  279. либо вернет то, что вернул метод apply в "случае успеха"...
  280.  
  281. Получается... Если ты передашь вейт антилу кондишен параметризированный типом Boolean
  282. то в случае успеха антил - вернет тру...
  283.  
  284. то есть ты можешь писать код вида:
  285.  
  286. if (wait.until(enabled(composeButton))) {
  287.    doSomething();
  288. }
  289.  
  290. но на самом деле, такое нужно не часто...
  291. то есть - такие кондишены - которые
  292. параметризированы типом булеан...
  293.  
  294. бошьше толку как раз от кондишенов параметризированных типом "того, характеристики чего ждет кондишен"...
  295.  
  296. вот кондишен visibilityOf - как раз параметризирован типом WebElement
  297.     ExpectedCondition<WebElement>
  298.  
  299. и его метод apply возвращает обьект типа WebElement,
  300. а "идейно" - возвращает этот же элемент, визибилити которого мы дожидались...
  301. (если бы мы не дождались - apply вернул бы null - что в этом случае играет роль "false")
  302.  
  303. а until в конце концов вернет то, что вернет apply
  304. и именно поэтому мы можем писать такой код:
  305.  
  306.     wait.until(visibilityOf(composeButton)).click()
  307. */
  308.  
  309. /*
  310.     Что почитать про Generics
  311.     про дженерики в общем(русский)
  312.     http://www.quizful.net/post/java-generics-tutorial
  313.  
  314.     http://www.tutorialspoint.com/java/java_generics.htm
  315.     http://developer.alexanderklimov.ru/android/java/generic.php
  316.  
  317.     конвеншенcы      http://stackoverflow.com/questions/2900881/generic-type-parameter-naming-convention-for-java-with-multiple-chars
  318.     https://docs.oracle.com/javase/tutorial/java/generics/types.html
  319.  
  320.     уроки
  321.     http://docs.oracle.com/javase/tutorial/extra/generics/index.html
  322.  
  323.     очень приличный faq (есть pdf, и есть кое-что еще, помимо дженериков)
  324.     http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html
  325.  
  326. */
  327.  
  328. /*
  329.     пока тольк вот это подправь
  330.     дальше продолжим
  331.     это еще не все)
  332. */
Advertisement
Add Comment
Please, Sign In to add comment