julia_v_iluhina

Untitled

Sep 16th, 2016
90
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 23.66 KB | None | 0 0
  1. /*
  2.     Ну, что сказать )
  3.     Уже много чего умеешь
  4.  
  5.     Но, как это ни странно звучит - пока что будем версию упрошать
  6.  
  7.     Конечно, не до примитивного состояния, которое собственно как решение и требовалось,
  8.     но до более простого - точно
  9.  
  10.     погугли  - premature optimisation is evil
  11.  
  12.     далее в комментариях - буду указывать не самый простой и самый простой вариант реализации
  13.     если будут сложности с реализацией не самого простого варианта - реализуй вариант попроще
  14.     и дальше по курсу - все будет) только чуть позже
  15. */
  16. *******************************
  17. src/main/java/com/selenide/core/TaskManager.java
  18.  
  19. /*
  20.     класс TaskManager - содержит в себе методы, которые являются инструментами =
  21.     это вспомогательные методы-действия для нашего приложения
  22.  
  23.     этот шаблон  - называют Page Objects
  24.     про это в контексте Selenide - см
  25.     http://ru.selenide.org/documentation/page-objects.html
  26.  
  27.     мы более подробно рассматриваем это на курсе - но не сразу, а уже выполнив несколько заданий
  28.     можешь оставить реализованный Page
  29.     с условием - что будут соблюдены все требования (опишу ниже)
  30.     если это покажется сложным - тогда - перенеси эти вспомогательные методы в тест-класс
  31.     (мера временная, до разбора собственно темы пейджей)
  32.  
  33.     что надо поправить - если оставить пейдж
  34.  
  35.         имя класса пейджа - должно заканчиваться на Page (согласно conventions)
  36.  
  37.         все верно, такой класс располагают в ветке проекта src/main/java
  38.         но только - в пекедже pages, а не core
  39.         core - для более универсальных вещей, применимых для тестов разных приложений
  40.  
  41.         что касается пекеджей com/selenide - тут я бы поспорила )
  42.         тут надо отразить - кто есть мы и что за проект мы делаем
  43.         если бы
  44.             мы = myOrganisation.com
  45.             проект = myProject
  46.         то получили бы такую структуру пекеджей
  47.             com/myorganisation/myproject
  48.  
  49.  
  50.         про это можно почитать в faq
  51.         https://docs.google.com/document/d/10qSwWTQ6pGfVZSwOes-1QSmdflMiGD2U_y53VHq2m20/edit#heading=h.o5zpntq2790p
  52.  
  53.  
  54.         чтобы переименовать класс
  55.         https://docs.google.com/document/d/10qSwWTQ6pGfVZSwOes-1QSmdflMiGD2U_y53VHq2m20/edit#heading=h.vwuqi54t6fyg
  56.  
  57. */
  58. ********************************************************
  59.     public void tasksCreator(int numOfTasks) {
  60.  
  61.         for (int i = 1; i <= numOfTasks; i++) {
  62.             $(By.id("new-todo")).setValue("task" + i).pressEnter();
  63.         }
  64.     }
  65.     /*
  66.         про имя метода - посмотри
  67.         https://docs.google.com/document/d/10qSwWTQ6pGfVZSwOes-1QSmdflMiGD2U_y53VHq2m20/edit#heading=h.o7vsh4r93b55
  68.  
  69.         что делаем - создаем/добавляем таски -
  70.          addTasks
  71.          createTasks
  72.  
  73.         параметр - int numOfTasks
  74.             ну, не лучший вариант )
  75.             а если мне понадобится тест, добавляющий таски "a", "b", "c"?
  76.             не надо внутри вспомогательных методов жестко диктовать - с какими тестовыми данными мы работаем
  77.             решение - какие тестовые данные мы используем - это решение, принимаемое в тест-методе
  78.             сравни код
  79.             addTasks(4);
  80.             vs
  81.             addTasks("task1", "task2", "task3", "task4");
  82.  
  83.             второй вариант - лучше
  84.             т к мы видим - что за таски мы создаем
  85.             нам для понимания этого - достаточно тест-метод прочитать
  86.             и не нужно углубляться в реализацию самого вспомогательного метода
  87.  
  88.             так что - это важное требование
  89.             во вспомогательых методах - оперируем только тем, что в метод передали как параметр
  90.             никаких решений о тестовых данных внутри вспомогательных методов быть не может
  91.  
  92.             реализуй этот метод по-другому
  93.                 чтобы можно было его вызвать вот так -
  94.                     addTasks("task1", "task2", "task3", "task4");
  95.  
  96.                 если сложно(буквально в следующей лекции будем разбирать - как) -
  97.                 то чтобы можно было его вызвать вот так
  98.                     addTask("task1");
  99.                     addTask("task2");
  100.                     addTask("task3");
  101.                     addTask("task4");
  102.  
  103.             в наиболее простом варианте - пока вообще не оперировать методами
  104.             просто в коде тест-метода -  $(...).setValue(...).pressEnter();
  105.  
  106.             только тут будь последователен
  107.             если от идеи использования методов отказываешься - то полностью)
  108.  
  109.             перепиши By.id("new-todo")
  110.             можно в метод $(...) - передавать строку - css селектор
  111.             получится лаконичнее
  112.  
  113.     */
  114. ********************************************************
  115.     public void markTaskAsCompleted(String taskName) {
  116.  
  117.         String labelXpath = "//label[contains(text()," + "'" + taskName + "'" + ")]/../input";
  118.         $(By.xpath(labelXpath)).click();
  119.     }
  120.     /*
  121.         про имя метода - можно лаконичнее - completeTask
  122.         но и это еще не все)
  123.         https://docs.google.com/document/d/10qSwWTQ6pGfVZSwOes-1QSmdflMiGD2U_y53VHq2m20/edit#bookmark=kix.x92tktmmfsz2
  124.         попробуй применить метод - completeTask к уже закомпличеной таске
  125.         получим - таска будет переоткрыта
  126.         т е - при другом контексте вызова метода - название метода не отражает того, что мы делаем
  127.         а это - плохо
  128.         подправь имя метода так - чтобы оно отражало суть действия вне зависимости от контекста
  129.         мы тут не комплитим, мы  - переключаем
  130.  
  131.         имя параметра - ну, можно и так
  132.             имя таски, текст таски - да, хорошие термины в данном случае
  133.  
  134.         по поводу использования xPath
  135.         да, инструмент мощный
  136.         да, в случае, когда нам нужно найти некий элемент по тексту - вроде бы альтернатив нет...
  137.  
  138.         но)
  139.  
  140.         во-первых
  141.             давай определимся - что мы ищем
  142.             мы в списке тасок ищем таску с таким-то именем
  143.             а внутри нее - ищем внутренний элемент такой-то
  144.  
  145.         когда нам еще придется работать со списком тасок
  146.             при удалении таски
  147.             при проверках состояния списка
  148.         т е - работать с сущностью - список тасок - мы будем в нескольких вспомогательных методах
  149.             погугли про DRY принцип
  150.             правильно - не повторять в коде - одинаковые независимые селекторы
  151.             т к - если потребуется менять код - то придется в нескольких местах вносить такие правки
  152.             потому - грамотнее объявить переменную ElementsCollection tasks = $$(....)
  153.                 ... - CSS selector списка тасок  - http://joxi.ru/v29WjP9hG6RnEr    
  154.             и далее - ее использовать в методах
  155.  
  156.             в самом примитивном варианте реализации этого задания - можно было
  157.                  для работы со списком тасок использовать $$("..."),
  158.                  
  159.                 если нужно что-то изнутри списка тасок - отталкивайся в любом случае от селектора списка тасок и его уже уточняй
  160.                  
  161.  
  162.                 опять же - в самом простом варианте (пока) - можно обратиться
  163.                  к элементу списка по его номеру
  164.                  и затем - уточниться до внутреннего элемента - переключателя
  165.                  это все можно сделать используя один css селектор - $(....)
  166.                  потом - разовьем
  167.                  пока - можно и так
  168.  
  169.                  как доступиться до нужного нам элемента $(...) - уточнить  css selector списка тасок
  170.                      список тасок
  171.                      такая-то по счету таска (поиск таски по тексту - можно отложить пока)
  172.                      такой-то элемент внутри таски
  173.                  далеко не идеально, но уже структурно - это позволит потом переделать код меньшими усилиями
  174.  
  175.             если пока с переменной - сложно
  176.             то - хотя бы вот так поступай
  177.                 везде, где отталкиваешься в рассуждениях от списка тасок - используй один и тот же селектор
  178.                 чтобы - когда дело дейдет до оптимизации кода - это легко было поправить
  179.  
  180.             а если пока с пониманием  - ок - то развиваем)
  181.             вообще, если сравнивать варианты
  182.                     для каждого элемента - свой независимый селектор
  183.                 или
  184.                     если элемент - часть уже обозначенной структуры - доступаемся к нему через эту структуру
  185.                 то - второй вариант дает больше преимуществ
  186.                 хотя бы потому - что читая такой код - понятнее - с чем мы имеем дело
  187.                 к этой теме мы будем еще возвращаться
  188.  
  189.             применительно к нашему случаю
  190.                 твой вариант = независимый селектор
  191.                     или
  192.                 вариант  tasks.findBy(....).find(...)
  193.                 то - второй вариант - лучше
  194.  
  195.                 чуть позже - как написать вот такой вариант tasks.findBy(....).find(...) - разберем
  196.                 но ты - попробуй разобраться сам. У тебя может получиться )
  197.  
  198.  
  199.         И еще важный и не сложный момент
  200.             input - не самый наглядный селектор для искомого элемента - переключателя состояния таски
  201.             подбери селектор понагляднее
  202.     */
  203. ***************************************************************
  204.     // this overloaded method marks all tasks as completed
  205.     public void markTaskAsCompleted() {
  206.  
  207.         for (SelenideElement label : $$(By.className("toggle"))) {
  208.             label.click();
  209.         }
  210.     }
  211. /*
  212.     тут требовалось выполнить действие - complete all
  213.     используя вот такой переключатель http://joxi.ru/gmvqJvkHxXeZer
  214.  
  215.     имя метода - можно попроще - completeAllTasks
  216.     но
  217.     посмотри как работает этот переключатель - кликни на нем, когда и так все таски закомпличены
  218.     так что - метод - не комплитит таски
  219.     а переключает их
  220.     учти это - когда будешь уточнять имя методу
  221.  
  222.     в этом методе к переключателям ты обратился как $$(By.className("toggle"))
  223.     а в прошлом методе - такие же переключатели идентифицировал как input
  224.     так лучше не делать
  225.     одно и то же  - получай одинаково.
  226.  
  227.     уже писала - методы $$ & $ - могут принимать в качестве параметра не только значение типа By
  228.     но и строку - css селектор
  229.     код получится попроще
  230. */
  231. *****************************
  232.     public void clearCompleted() {
  233.  
  234.         $(By.id("clear-completed")).click();
  235.     }
  236. /*
  237.     перепиши $(By.id("clear-completed")) - используй css селектор как параметр для метода $
  238.  
  239.     правда, не хочется в имени метода указывать Tasks?
  240.  
  241.     на самом деле - в этом простеньком приложении - все операции = операции над тасками
  242.     потому - можно из имен вспомогательных методов действий поубирать Tasks/Task -
  243.     add, delete, ...
  244.     не станет хуже от этого - т к по-прежнему - все однозначно
  245.     мы знаем - что работаем с  тасками
  246.  
  247.     хоть еще ни одного метода с проверками не реализовано
  248.     скажу на будущее
  249.     в именами методов проверок - так лучше не делать
  250.     тут - надо четко указать что конкретно проверяем
  251.     во-первых - однозначность очень важна
  252.     во-вторых - даже для такого простого случая - у нас будет не единственная проверка
  253.     так что  - важно быть точным в формулировках
  254. */
  255. *************************************
  256.     public void deleteTask(String taskName) {
  257.  
  258.         String focusOnTheTask = "//*[contains(text()," + "'" + taskName + "'" + ")]/..";
  259.         SelenideElement deleteButton = $(By.xpath(focusOnTheTask)).hover();
  260.         String focusOnDelete = "//*[contains(text()," + "'" + taskName + "'" + ")]/../button";
  261.         deleteButton.$(By.xpath(focusOnDelete)).click();
  262.     }
  263. /*
  264.     обойдись без xpath
  265.     либо вариант продвинутый - tasks.findBy(...) - в списке тасок нашли таску по ее тексту
  266.     либо вариант попроще $(...) - ... - селектор для такой-то таски в списке тасок (обратиться к таске по ее номеру - приемлемо для этой версии)
  267.  
  268.  
  269.     то же относится и к кнопке для удаления таски
  270.     к ней тоже - доступись одним из выше описанных способов
  271.  
  272.  
  273.     кнопку удаления - лучше идентифицировать по чему-то более наглядному (button - мало что проясняет)
  274. */
  275. ****************************************************
  276.  
  277.     public void clickAll() {
  278.  
  279.         $(By.className("selected")).click();
  280.     }
  281. /*
  282.     вот это - не понятно - зачем
  283.    
  284.     мы в данном сценарии - никуда с all фильтра и не уходили
  285.  
  286.     ну а на будущее - надо бы для такого метода - имя пооднозначнее
  287.     например - filterAll
  288.     по названию - clickAll() - я не смогла понять - что имелось в виду
  289.     пока не посмотрела на его реализацию
  290.  
  291.     а чтобы доступиться к элементу http://joxi.ru/L210nzMu64wM0m
  292.     есть куда более наглядные и точные способы
  293.     $(By.linkText(...)) например
  294. */
  295. *******************************
  296. public class BaseTest {
  297.  
  298.     protected TaskManager testEntity = new TaskManager();
  299.  
  300.     @BeforeClass
  301.     public static void setUp() {
  302.  
  303.         open("https://todomvc4tasj.herokuapp.com/");
  304.     }
  305.  
  306.     @AfterClass
  307.     public static void tearDown() {
  308.  
  309.         close();
  310.     }
  311. }
  312. /*
  313.     предка для тест-класса - тебе точно не нужно
  314.  
  315.     создавать пейдж-объект в предке класса = скрывать важное
  316.     а это плохо
  317.     создавай пейдж-объект в рамках самого тест-класса
  318.  
  319.     выносить код в @BeforeClass (=сделать единожды перед запуском всех тест-методов класса)
  320.     когда у тебя всего один тест-метод (именно это просили в задании - реализовать один тест-метод)
  321.     и ты не знаешь - нужно ли будет это в других тест-методах -
  322.     очень преждевременное решение
  323.     строку  open("https://todomvc4tasj.herokuapp.com/"); - размести в начале тест-метода
  324.  
  325.     закрывать вебдрайвер не нужно
  326.     Selenide сам об этом позаботится
  327.  
  328.     имя пейджа-объекта
  329.         про имя класса для пейджа - уже обсудили
  330.         имя объекта - тоже должно отражать - что это
  331.         если пейдж-объект один - можно назвать переменную page
  332.  
  333.         можно - отразить что это
  334.         для пейджа класса TodoMVCPage
  335.         будет ок - tasks, todoMVC
  336. */
  337. ****************************************
  338.  
  339. @FixMethodOrder(MethodSorters.NAME_ASCENDING)
  340. public class TodoMVCTest extends BaseTest {
  341. /*
  342.     это вредная практика - диктовать порядок запуска тестов
  343.     тест-методы должны быть независимыми друг от друга
  344.  
  345.     в данном случае - мы решаем задачу - автоматизировать такой-то тестовый сценарий
  346.     для этого нам нужен один тест-метод - с несколькими шагами
  347.    
  348.     как писать тест-методы, тестирующие одно конкретное действие - тоже будет на курсе
  349.     разговор тут подлиннее )
  350.     потому - реализуй именно один тест-метод
  351.    
  352.     также не забывай - что цель тестирования - проверить - что дейтсиве не только выполняется,
  353.     но и выполняется с нужным тебе результатом
  354.     проверки - важны
  355.     и откладывать их не стоит, по крайней мере надолго
  356.     т к нам важно понимать - что конкретно работает не верно
  357. */
  358.     @Test
  359.     public void test1TaskCreator() throws InterruptedException {
  360.  
  361.         testEntity.tasksCreator(4);
  362.     }
  363.     /*
  364.         для чего throws InterruptedException ?
  365.        
  366.         после добавления тасок - нужна проверка
  367.         касается и других действий
  368.     */
  369. **********************
  370.     @Test
  371.     public void test3MarkTheTaskAsCompleted() throws InterruptedException {
  372.  
  373.         testEntity.clickAll();
  374.         testEntity.markTaskAsCompleted("task4");
  375.     }
  376. /*
  377.     не могу понять - зачем  clickAll()?
  378. */  
  379. ***********************************************
  380.     @Test
  381.     public void test4DeleteCompleted() throws InterruptedException{
  382.  
  383.         testEntity.clearCompleted();
  384.     }
  385. /*
  386.     не применяй для одного понятия - разные термины
  387.     DeleteCompleted и clearCompleted
  388.    
  389.     clearCompleted - хороший термин
  390.     он точный и наглядный - т к взят с User Interface
  391.    
  392.     ниже  - ты 2 действия объединил в один метод - complete all + clear completed
  393.     тут - так делать не стал)
  394.    
  395.     напоминаю - мы пишем один тест-метод с несколькими шагами
  396.    
  397.     вот для шагов
  398.         complete + clear completed
  399.         complete all + clear completed
  400.     будет приемлемо проверку делать после clear completed
  401.     т е - отложить  проверку после закомпличивания на 1 шаг
  402.     т к на all фильтре закомпличивание тасок проверить точно - сложно
  403.     а в целом - правило такое - каждое действие должно быть проверено сразу    
  404.    
  405.     так что - твоя идея объединить эти 2 действия в один блок -
  406.     все же может быть востребованной)
  407.     правда, с учетом того - что вс это мы делаем в одном тест-методе
  408. */    
  409.  
  410.     @Test
  411.     public void test5MarkAndDelete() throws InterruptedException{
  412.  
  413.         testEntity.markTaskAsCompleted();
  414.         testEntity.clearCompleted();
  415.     }
  416.    
  417.  
  418. }
Advertisement
Add Comment
Please, Sign In to add comment