julia_v_iluhina

Untitled

Dec 30th, 2016
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 23.40 KB | None | 0 0
  1. https://github.com/AleksanderPopov/automician_course/blob/master/questions_and_review/3_code_questions.txt
  2.  
  3. ===============================================================================
  4. 1. "private By tasks = By.cssSelector("#todo-list li");
  5.    //можно проще
  6.    private ElementsCollection tasks = $$("#todo-list li");
  7.    //а еще лучше - вот так
  8.    private ElementsCollection tasks = $$("#todo-list>li");"
  9.  
  10.             >>>>>>>> так лучше локаторы хранить, или коллекции? в статье Солнцев
  11.                     писал что если бы ему нужно было бы переиспользовать элемент,
  12.                     он бы сохранил локатор как поле...
  13. /*
  14.     мы рекомендуем хранить коллекцию
  15.     для селениде - это ничем не хуже
  16.  
  17.     по сути переменная - ElementsCollection tasks - ничем не хуже локатора
  18.     объявляя и инициализируя ее - мы просто описываем - что и как мы будем искать
  19.     когда это понадобится
  20.     т е по сути - эта часть функциональности - очень похожа на локаторы
  21.     т е - ничем не хуже
  22.  
  23.     а еще - когда начнем работать с ElementsCollection tasks - будем писать меньше кода
  24.     что тоже приятный бонус)
  25.  
  26.     так что - оперируй переменными типов ElementsCollection и SelenideElement - без проблем
  27.  
  28.     по той статье - там ты видел  - какой код Солнцев комментировал)
  29.     http://automation-remarks.com/2016/selenide-shadow-sides/index.html
  30.  
  31.     если будешь отдельно - открывать урл
  32.     и отдельно - инициализировать пейдж
  33.     то проблем с использованием полей типа ElementsCollection и SelenideElement - точно не будет
  34.  
  35.     Если нравится вариант  - когда вынесены в переменные именно локаторы
  36.     а уже в самих методах - мы получаем по этим локаторам - элемент или коллекцию
  37.     то это в общем тоже ОК
  38.     Особенно с учетом - что так сам автор Selenide говорит)
  39.     Я вижу в таком подходе такие плюсы
  40.         решение очень похоже на чистое селениумское решение (грамотное)
  41.         там тоже - лучший вариант - не через @FindBy прокси элементы/списки работать
  42.         и именно - испольуя локаторы
  43.         но то мы попозже поговорим про Selenium
  44.  
  45.         и второй момент
  46.         по имени переменной tasks - типа - еще догадаться нужно - что оно такое
  47.         в отличие от $$(tasks)
  48.  
  49.     Однако - я остаюсь при своем мнении)
  50.        я в своем коде - использую именно переменные типа ElementsCollection и SelenideElement
  51.        (ну или в методах - зашиваю работу с $$(....) $(....) - если селектор лишь для реализации этого метода нужен
  52.        то никаких переменных не нужно вообще)
  53.  
  54.        причина проста - мы и так на уровне тестовой логики оперируем неким набором формальных понятий
  55.        и от того, что у нас к тому же будет более формализована работа с переменными - я не вижу проблемы
  56.        (tasks или $$(tasks) - я выберу tasks - т к в переменные мы выносим то, что используется не единожды
  57.        это не представляет труда запомнить - что за сущность. А писать - чуть меньше))
  58.  
  59.        Яков тоже так поступает, как я описала)
  60.  
  61.        Технически - отлично все работает - когда ты оперируешь переменными типа ElementsCollection и SelenideElement
  62.        когда инициализаия пейджа не сопряжена с открытием урла
  63.        я так и делаю - открываю урл отдельно, пейджи инициализирую отдельно
  64.        и все ок)
  65.  
  66.        Если тебе покажется лучшей идея - оперировать локаторами
  67.        ну... наверное я не буду спорить)
  68.        но я так точно не стала бы делать)
  69.  
  70. */
  71. ===============================================================================
  72. 2. "что касается селектора "#todo-list>li"
  73.        то он - точнее
  74.        для нашего примитивного прилодения - и твой вариант ок
  75.        но иногда эта разница бывает существенной"
  76.  
  77.             >>>>>>>> да, я знаю в чем разница) конкретно в этом случае не нужно
  78.                     было искать элемент непосредственно на уровень ниже я и не
  79.                     стал.
  80. /*
  81.     да, я писала про это
  82.     что и твой вариант ок
  83.     в данном случае)
  84. */
  85. ===============================================================================
  86. 3. "вариант обхода - for (SelenideElement e : $$(tasks))
  87.        плох тем, что на момент старта обхода - на странице  могут  еще недогрузиться элементы в списке
  88.        получается - ненадежно и код раздутый"
  89.  
  90.             >>>>>>>> в смысле недогрузится? я думал когда мы обращаемся к
  91.                     $$(tasks) он сначало находит все, что может, а потом уже
  92.                     отдает нам коллекцию, разве не так?
  93.  
  94.                     ***********************************
  95.                     for (SelenideElement e : $$(tasks))
  96.                     ***********************************
  97.  
  98.                     и
  99.  
  100.                     ***********************************
  101.                     ElementsCollection c = $$(tasks);
  102.                     for (SelenideElement e : c)
  103.                     ***********************************
  104.  
  105.                     не одно и то же чтоли? типа в первой ситуации это ненадежно,
  106.                     а во второй надежно?
  107. /*
  108.     оба варианта, которые ты привел - одинаково ненадежны)
  109.  
  110.     $$(tasks) - лишь рассказ про то - как искать коллекцию
  111.  
  112.     $$(tasks) - мы начинаем ее обход, и получим коллекцию, которая есть на этот момент
  113.     ты знаешь универсальный способ определить - что коллекция догрузилась?
  114.     любая коллекция, сферическая в вакууме )
  115.  
  116.     а как мы работаем обычно - как юзеры
  117.     мы что - ждем сидим этого - что что-то догрузилось
  118.     обычно - как только мы видим нужные нам элементы - мы начинаем с ними взаимодействовать
  119.     не более того, никаких ожиданий - когда загрузится все и вся - мы не делаем
  120.  
  121.     чтоб с чем-то взаимодействовать - нам достаточно - чтоб это у нас было
  122.  
  123.     использовать обход коллекции, чтоб проверить все ее элементы - это неудачный подход
  124.     используй should - проверки для коллекции
  125.     можешь полюбопытствовать  - как это устроено
  126.     в should- проверке в рамках таймаута - выполняются проверки коллекци по кондишену
  127.  
  128.     что фактически происходит
  129.     например, мы задали проверку collection.shouldJave(size(....))
  130.  
  131.     в рамках таймаута
  132.         получаем список вебэлементов - по информации о collection (ты помнишь - по сути - это рассказ о том, как получать список элементов)
  133.         если его размер равен ожидаемому - все, проверка прошла
  134.         все ок
  135.         если нет - ожидаем миллисекунды (нет смысла без задержки новую проверку делать - только ресурсы жрать)
  136.         и снова проверяем
  137.  
  138.         если в таком цикле в рамках таймаута - проверка не прошла - наш тест падает
  139.         если прошла - проходит
  140.  
  141.     мы, вызывая проверку   collection.shouldJave(size(....)) - сами задаем -
  142.     чего нам нужно дождаться/что ам нужно проверить
  143.  
  144.     в то же время, у коллекции есть метод size()
  145.     он вернет - тот размер, которій у коллекции есть на момент вызова этого метода
  146.  
  147.     итого - проверки для коллекции - делай не через обход ее элементов в цикле
  148.     а через работу с should - проверками для коллекции
  149.     автор теста лучше всех знает - чего ему нужно дождаться
  150.  
  151.     а если говорить о доступе к конкретному элементу коллекции
  152.     то тоже - не нужно его искать в цикле
  153.     получи нужный элемент этой коллекции
  154.     через уточнение
  155.     SelenideElement element = collection.get(...)
  156.     SelenideElement element = collection.findBy(...)
  157.  
  158.     это по сути - рассказ - как получить элемент (в этот момент мы еще ничего не получаем)
  159.     а вот когда начнем взаимодействовать с элементом (кликать, значение вводить и прочее)-
  160.     то сначала будет выполнено ожидание его видимости (аналогичная ждущая проверка)
  161.     и потом - работа с ним
  162.     т е - очень похоже на то, что делает человек, работая с сайтом
  163.     увидел нужное ему - и давай юзать)
  164.  
  165.     такие обходы - for (SelenideElement e : $$(tasks)) - теоретически
  166.     я бы делала после того - как выше по коду дождалась нужного мне
  167.     но - пока прецедентов не было)
  168.     реально - имея выше описанные способы работы - это пригодится крайне редко
  169.     если вообще пригодится)
  170.  
  171.     код - когда ты юзаешь проверки, или когда ты доступаешься к элементам коллекции через методы этой коллекции - проще, чище, надежней
  172.     все сложности и ухищрения - все под капотом
  173.     тебе остается думать о тестовой логике
  174.     что очень приятно - ведь решать одну задачу вместо нескольких - проще
  175. */
  176. ===============================================================================
  177. 4. "что до реализации метода
  178.        его конечно реализовывать - не нужно было
  179.        но уже если делать - то чтоб он был надежнее и проще - лучше сделать вот так
  180.        for (String taskName : taskNames) {
  181.            destroy(taskName);
  182.        }
  183.        и все)"
  184.  
  185.             >>>>>>>> я специально отдельно реализовал, для того чтоб если вдруг
  186.                     нам понадобится удалить 100 тасок, мы не 100 раз переискивали
  187.                     весь список, а один.
  188. /*
  189.     нам такого не понадобится)
  190.     по крайней мере - пока мы не решим реализовывать нагрузочное тестирование таким способом)
  191.     а это довольно экзотичный способ будет (хотя наверное - и такой имеет право на существование)
  192.     и там в проекте еще понадобятся дополнительные инструменты - нам же еще и намерять нужно - что мы нагрузили
  193.     то - отдельная тема
  194.     и в курсе мы этого не касаемся - нагрузочного тестирования
  195.  
  196.     для функционального тестирования - мотивы я описала в ревью ранее - почему нам не нужен такой метод
  197. */
  198. ===============================================================================
  199. 5. "чтобы избежать этого
  200.        вместо переменных стоит использовать методы
  201.        тогда для каждого вызова кондишена мы будем использовать свой объект
  202.        и таких проблем не будет"
  203.  
  204.             >>>>>>>> это как? я чет не понимаю о чем речь, в том же селениде
  205.                     все описано либо так
  206.                     *************************************
  207.                       public static final Condition hidden = new Condition("hidden", true) {
  208.                         @Override
  209.                         public boolean apply(WebElement element) {
  210.                           try {
  211.                             return !element.isDisplayed();
  212.                           } catch (StaleElementReferenceException elementHasDisappeared) {
  213.                             return true;
  214.                           }
  215.                         }
  216.                       };
  217.                     *************************************
  218.                     либо так
  219.                     *************************************
  220.                       public static Condition matchText(final String regex) {
  221.                         return new Condition("match text") {
  222.                           @Override
  223.                           public boolean apply(WebElement element) {
  224.                             return Html.text.matches(element.getText(), regex);
  225.                           }
  226.                           @Override
  227.                           public String toString() {
  228.                             return name + " '" + regex + '\'';
  229.                           }
  230.                         };
  231.                       }
  232.                     *************************************
  233.                     у меня описано инициализация переменной как в случае 1
  234.                     т.к. мне не нужно параметры передавать в ajaxCompleted.
  235.                     Добавил final На всякий случай, хотя эту переменную всу
  236.                     равно должны только читать, используя свой инстанс драйвера.
  237.                     Или ты имеешь ввиду вместо переменной ajaxCompleted сделать
  238.                     метод, который её возвращает, т.к. вызывать мы его будем
  239.                     только в хелпере, в методе waitForAjaxCompleted()?
  240. /*
  241.     Да, ты прав, в Selenide - именно так и есть - такого рода кондишены - объявлены как статические переменные
  242.     и в общем - это может быть источником проблем при паралльной работе тестов - если кондишен оперирует какими-то
  243.     переменными-состояниями (как например - у тебя - переменная result)
  244.  
  245.     public static final ExpectedCondition<Boolean> ajaxCompleted = new ExpectedCondition<Boolean>() {
  246.             boolean result;
  247.  
  248.             @Override
  249.             public Boolean apply(WebDriver driver) {
  250.                 try {
  251.                     result = (Boolean) ((JavascriptExecutor) driver).executeScript("return typeof($) !== 'undefined' && $.active == 0");
  252.                     System.out.println("Ajax return $.active == 0  is: '" + result + "'");
  253.                 } catch (Exception e) {
  254.                     return false;
  255.                 }
  256.                 return result;
  257.             }
  258.  
  259.             public String toString() {
  260.                 return "Ajax return $.active == 0  is: '" + result + "'";
  261.             }
  262.         };
  263.  
  264.     ajaxCompleted = один объект
  265.     и если его одновременно будут в разных потоках - дергать
  266.     то это поле - result - будет отражать состояние - то для одного потока, то для другого
  267.     конечно - на такие грабли - наступить тяжеловато, но возможно
  268.  
  269.     а если объявить метод
  270.     public static final ExpectedCondition<Boolean> ajaxCompleted() {
  271.      return new ExpectedCondition<Boolean>() {
  272.      ...
  273.  
  274.     то - для каждого вызова проверки такого кондишена - будет свой отдельный объект-кондишен
  275.     и таких проблем гарантированно не будет
  276.  
  277.     реализуй кондигены методами - даже если у них нет параметров - ajaxCompleted()
  278.     этот вариант правильнее
  279. */
  280. ===============================================================================
  281. 6. "public TaskPage completedShouldHaveTexts(String... texts) {
  282.    public TaskPage completedListShouldBeEmpty() {
  283.    /*
  284.        Методы реализованы пристойно
  285.  
  286.        но - они все равно не нужны)
  287.        про это Яков говорил в видео
  288.        https://drive.google.com/file/d/0B8hgIBw8-V-AUDhxWDg1YmYxM3c/view?usp=sharing
  289.        примерно с 58-ой минуты, минут 5-7 посмотри"
  290.  
  291.             >>>>>>>> типа мы сейчас пишем функциональные тесты, поэтому нет
  292.                     смысла проверять что к задачке добавился класс, а лучше
  293.                     проверить функционал toggle -> filter, clearCompleted ?
  294. /*
  295.     мы и сейчас, и далее везде на курсе - пишем функциональные тесты)
  296.     и да, верно, закомпличивание можно проверить тобой описанными способами
  297.     этого касалась и в ревью на твой сценарий
  298.     думаю, уже вопросы должны были отпасть
  299. */
  300. ===============================================================================
  301. 7. "а вот с destroy("2", "3") - другая история уже
  302.    тут пропуск проверки повлияет на точность проверок"
  303.  
  304.         >>>>>>>> почему повлияет? если мы пытаемся удалить например 2,
  305.                 а удаляется 3-я, мы поймем т.к. не найдем элемент. Если просто
  306.                 ничего не удаляется, или удаляется не то, то тоже поймем, т.к.
  307.                 после удаления проверяем что осталось. Где же мы тогда потеряли
  308.                 по точности?
  309. /*
  310.     тут вариантов - много на самом деле - как и что может пойти не так
  311.     общее правило такое - каждая операция должна быть проверена сразу
  312.  
  313.     а покрывать дважды подряд удаление - я даже для full coverage - не вижу смысла
  314.     разумнее в разных тестовых ситуациях и на разных контекстах удалить по одной таске и проверить эти результаты
  315.     ну то уже будем делать - когда full coverage будем реализовывать
  316.  
  317.     в общем - бесполезная функиональность - метод delete с несколькими параметрами
  318.     в данном случае)
  319.    
  320.     конечно, в жизни будет куча задач - когда действительно - понадобятся методы
  321.     заполняющие сразу кучу полей, или включающие кучу переключателей
  322.     т к у нас - на эти поля и секбоксы = может быть какая-то одна неразделимая логика =
  323.     заполнили + наклацали и только потом поверили
  324.      
  325.     но в даном случае = удаление таски = отдельно проверяемое действие, со своей отдельной логикой
  326.    
  327. */
  328. ===============================================================================
  329. 8. "не понимаю ценности BaseTest поясни, что из реализованного в BaseTest - ценно"
  330.  
  331.         >>>>>>>> ну как минимум он нужен для 'Configuration.browser = "firefox";'
  332. /*
  333.     по умолчанию - так оно и есть)
  334.     потому - ничего и не нужно делать
  335. */        
  336. ===============================================================================
Advertisement
Add Comment
Please, Sign In to add comment