Advertisement
julia_v_iluhina

Untitled

Jan 11th, 2017
125
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 43.04 KB | None | 0 0
  1. public class OpenTodoMVCAndClearData extends BaseTest {
  2. /*
  3.     Предков тест-класса - называй по тем же конвеншенсам что и сами тест-классы -
  4.     имя класса должно заканчиваться на Test
  5.     На видео Якова - было более удачное название для этого класса
  6.  
  7.     Ну то пока не исправляй)
  8.     От этого класса избавимся в итоге)
  9. */
  10.     protected TaskPage page = new TaskPage();
  11. /*
  12.     Прятать создание пейджей в предке тест-класса - не хорошая практика,
  13.     особенно в общем случае - когда у нас несколько пейджей
  14.  
  15.     На самом деле - для разных тест-классов - может понадобиться разный набор пейджей
  16.     Потому - создавать весь набор инструментов - вроде как перебор
  17.  
  18.     Да и скрываем мы это - в тест-классе не ясно - что за пейдж и откуда он берется
  19.  
  20.     Вот если использовать некую одну точку входа - тут создавать некий объект
  21.     с помощью которого можно будет получить доступ к любым пейджам - так оно будет более оправдано
  22.     Если, конечно, пейджей больше одного)
  23.     Да и создание такой точки входа - лучше вынести в отдельный предок тест-класса
  24.     тк  - Single Responsibility principle
  25.  
  26.     Почитай вот тут - диалог Якова и студента, который аналогичное решение применял
  27.     http://pastebin.com/qP85P1SP
  28.     думаю, вопросы должны отпасть
  29.  
  30.     Далее - когда мы с виджетами будем разбираться - как раз вариант с единой точкой входа проработаем
  31. */
  32.  
  33.     @Before
  34.     public void openPage() {
  35.         page.visit();
  36.         getWebDriver().navigate().refresh();
  37.         /*
  38.             про рефреш - писала
  39.             просто - refresh()
  40.         */
  41.     }
  42.  
  43.     @After
  44.     public void clearData() {
  45.         clearLocalStorage();
  46.     }
  47.     /*
  48.         тут - ты тоже не послушался)
  49.         нет смысла выносить код отдельно в Helpers.clearLocalStorage
  50.         ведь только здесь это и нужно
  51.         и это - только одна строка кода
  52.  
  53.         имхо, слишком много суеты вокруг одной строки кода)
  54.  
  55.         ну то еще на твои вопросы с комментариями посмотрю
  56.     */
  57. }
  58. ******************************************************************************
  59.     @Attachment(value = "Page-screenshot", type = "image/png")
  60.     private byte[] publishScreenshot() {
  61.         File screenshot = Screenshots.takeScreenShotAsFile();
  62.         try {
  63.             byte[] arr = readAllBytes(Paths.get(screenshot.toURI()));
  64.             screenshot.delete();
  65.             return arr;
  66.         } catch (IOException | NullPointerException e) {
  67.             System.err.println("Exception occurred while trying to read from screenshot file." +
  68.                     "\n cause: " + e.getCause());
  69.         }
  70.         return new byte[0];
  71.     }
  72. /*
  73.     я вижу - что сейчас этот код ты не используешь
  74.  
  75.     все равно прокомментирую
  76.     ловить NullPointerException - считается bad practice
  77.     правильнее - делать проверки и обходить
  78.     http://stackoverflow.com/questions/15146339/catching-nullpointerexception-in-java
  79.     https://examples.javacodegeeks.com/java-basics/exceptions/java-lang-nullpointerexception-how-to-handle-null-pointer-exception/
  80.  
  81.  
  82.     http://howtodoinjava.com/core-java/exception-handling/how-to-effectively-handle-nullpointerexception-in-java/
  83.  
  84.     вот это - горячо рекомендую
  85.     http://www.yegor256.com/2014/05/13/why-null-is-bad.html
  86.     особенно вот это http://joxi.ru/5md7jYwtvV5k8r
  87.  
  88.     почему самому не стоит вызывать NPE
  89.     http://stackoverflow.com/questions/4715492/best-practise-in-catching-and-throwing-nullpointerexception
  90.  
  91.     на самом деле - таких проблем с Screenshots.takeScreenShotAsFile() - и не должно быть
  92.     это с getLastScreenshot такое запросто может случиться - если нет автоматически сделанного скриншота - именно нуллл метод и вернет
  93.     про это есть в faq
  94.     https://docs.google.com/document/d/13dNyFGbI7mV22UUhH8E0LJ7SzabAmX7Bw7VCHScYfiU/edit#heading=h.c6yq8ne03bpo
  95.     см соответствующий раздел
  96. */
  97. **********************************
  98. public class AllureScreenPublisher extends TestWatcher {
  99.     private final Logger log = Logger.getLogger(getClass().getName());
  100.     private boolean onFail = false;
  101.     private boolean onSuccess = false;
  102.  
  103.     private AllureScreenPublisher() {
  104.     }
  105.  
  106.     public static AllureScreenPublisher getInstance() {
  107.         return new AllureScreenPublisher();
  108.     }
  109.  
  110.     public AllureScreenPublisher onFail() {
  111.         this.onFail = true;
  112.         return this;
  113.     }
  114.  
  115.     public AllureScreenPublisher onSuccess() {
  116.         this.onSuccess = true;
  117.         return this;
  118.     }
  119.  
  120.     public AllureScreenPublisher always() {
  121.         this.onSuccess = true;
  122.         this.onFail = true;
  123.         return this;
  124.     }
  125. /*
  126.     можно было и тут сделать объект не мутабельным
  127.     реализовав
  128.      private-конструктор с этими 2-мя параметрами - onFail и  onSuccess
  129.      и публичные статические методы   onFail()/onSuccess()/always()
  130.      которые фактически - и будут создавать объект с нжной тебе комбинацией свойств
  131.  
  132.     и вместо вызова - AllureScreenPublisher.getInstance().always();
  133.     будет - AllureScreenPublisher.always();
  134.  
  135.     названия для методов onFail()/onSuccess()/always() - можешь подобрать точнее
  136.     если хочешь отразить - что мы объект создаем
  137.     мне кажется - и так будет очень ок
  138.  
  139. */
  140. *************************
  141. if (onSuccess) publish();
  142. /*
  143.     согласно conventions - фигурные скобки и в таких случаях нужно применять
  144.      https://google.github.io/styleguide/javaguide.html#s4.1.1-braces-always-used
  145.     тоже - этот документ рекомендую, дельный
  146. */
  147. ****************************
  148.     Attachment(value = "Page-screenshot", type = "image/png")
  149.     public byte[] publish() {
  150.         String path = screenshot();
  151.         log.info(path);
  152.         // skip 'Screenshot: file:/'
  153.         path = path.substring(19, path.length());
  154.  
  155.         File screenshot = new File(path);
  156.         try {
  157.             byte[] arr = readAllBytes(Paths.get(screenshot.toURI()));
  158.             System.err.println("Delete screenshot: " + clean(path));
  159.             return arr;
  160.         } catch (IOException | NullPointerException e) {
  161.             System.err.println("Exception occurred while trying to read from screenshot file." +
  162.                     "\n cause: " + e.getCause());
  163.         }
  164.         return new byte[0];
  165.     }
  166. /*
  167.     не могу понять - зачем столько сложностей
  168.  
  169.     почему не использовать Screenshots.takeScreenShotAsFile();
  170.     зачем удалять файлы - если  - mvn clean - прекрасно зачищает все это
  171.  
  172.     про эксепшены - читай выше
  173.  
  174.     и я бы - не использовала catch-секцию
  175.     а указала для метода - throws IOException
  176.  
  177.     если будет проблема - пусть будут кишки наружу
  178.     сообщение мы можем спокойно пропустить
  179.     и так и не узначем - что там у нас было
  180. */
  181. ***********************************
  182.     public boolean clean(String pathToPng) {
  183.         String pathToHrml = pathToPng.substring(0, pathToPng.lastIndexOf('.')).concat(".html");
  184.         return new File(pathToHrml).delete() & new File(pathToPng).delete();
  185.     }
  186. /*
  187.     из практики совет
  188.     раз уже разрыл - что и html с таким же именем может быть)
  189.  
  190.     иногда - вот этот html - тоже очень полезная штука
  191.  
  192.     париться с его удалением - точно не стоит
  193.     а вот и его приаттачить, вместе с картинкой - может быть очень полезно)
  194.  
  195.     лучшего способа - чем ты реализовал - для доступа к html - я не знаю
  196.     может он и есть, конечно
  197.     но - имей в виду - из этих лимонов - можно надавить лимонад)
  198.  
  199.     что я хочу сказать)
  200.     clean - лишнее
  201.     т к mvn clean - вполне справляется с задачей
  202.     это надо убивать
  203.  
  204.     стоит использовать Screenshots.takeScreenShotAsFile();
  205.     так проще код будет
  206.  
  207.     а если понравилась идея про - аттачить  html
  208.     то
  209.     переименуй этот класс - т к речь не только про скриншот
  210.     и аттачь - и скриншот и html (2 метода аннотированные как Attachment)
  211.     это - не обязательно
  212.     да и я тебе не скажу - формируется ли html - если мы вызываем метод для формирования скриншота
  213.     возможно - это пара для getLastScreenshot - при падениях тестов - точно и скриншот и html формируется
  214.  
  215.     в оригинальном задании - нужно было аттачить скриншот всегда к тесту
  216.     это уже ты сделал, причем разными способами
  217.  
  218.     на практике - мне пригождалось 2 режима
  219.         аттачить скриншот вообще к степу (бывают такие степы - что горошо бы и картинку увидеть)
  220.         аттачить скриншот если тест упал - по финишу
  221.  
  222.     можно вот эти все фантазии - не реализовывать
  223.     просто помни - что иногда это полезно может быть
  224.  
  225.     минимально к ревью
  226.         - упрости решение
  227.         - не лови null pointer exception
  228.         - уйди от мутабельности
  229.         - не убивай файлы
  230.         - не лови IOException
  231.  
  232.     максимально к ревью (можно не делать, это только если видишь практическую пользу для себя)
  233.         - аттачить как скриншот так и ???html - если он сформировался)
  234.         - возможность аттачить на любом степе теста (это не сложно - вызывай в степ-методе - метод с аннотацией Attachment)
  235.  
  236. */
  237. *****************************************************************
  238. *****************************************************************
  239. public enum FilterType {
  240.     ALL,
  241.     ACTIVE,
  242.     COMPLETED
  243. }
  244.  
  245. public enum TaskType {
  246.     ACTIVE,
  247.     COMPLETED
  248. }
  249.  
  250.  
  251. public class Helpers {
  252.  
  253.     public static void waitUntilAjaxComplete() {
  254.     public static void waitUntilAjaxComplete(long timeoutMills) {
  255.     public static void clearLocalStorage() {
  256.  
  257.     public static PreConditionsBuilder givenAtTodoMvc() {
  258.     public static class PreConditionsBuilder {
  259.     }
  260. }
  261.  
  262. /*
  263.     смешались в пекедже - src/main/java/com/alexautomician/todomvc/api вообще
  264.     и в классе - Helpers - в частости
  265.     кони и люди) мухи и котлеты)
  266.  
  267.     я бы не сказала - что нужное нам для реализации гивенов - относится к src/main/java/com/alexautomician/todomvc/api
  268.     выдели для этого - отдельный пекедж - src/main/java/com/alexautomician/todomvc/givenhelpers к примеру
  269.  
  270.     и там расположи - FilterType, TaskType и класс givenHelpers
  271.     поскольку - и FilterType и TaskType - нужны только для гивен-методов
  272.     я бы и их запихнула как иннер-классы в givenHelpers
  273.  
  274.     но то такое, не настаиваю
  275.  
  276.     просто - придерживайся одной линии
  277.     или все аккуратненько держи в givenHelpers
  278.     или все аккуратненько разложи в src/main/java/com/alexautomician/todomvc/givenhelpers
  279.     вопрос - что есть для тебя - аккуратненько)
  280. */
  281. *********************************************************
  282.     public static class PreConditionsBuilder {
  283. /*
  284.     твой вариант - это не Builder pattern
  285.  
  286.     там же вся соль в том - что один объект = который мы строим = не мутабельный
  287.     мы его собираем с помощью билдера
  288.     и потом - работаем с ним
  289.  
  290.     и есть объект = билдер - он мутабельный
  291.     он только и делает - что собирает нужные свойства для будущего объекта
  292.     и затем - строит этот объект - разово отдавая ему все собранные свойства
  293.  
  294.     каждый объект - выполняет свою роль
  295.     один - строит
  296.     второй - используется
  297.  
  298.     стоит переделать - т к такая реализация будет правильнее
  299.     такой код - проще в итоге сопровождать, развивать и дорабатывать
  300.     (хотя, когда его пишешь с нуля - согласна - так не кажется, хочется вот так сэкономить)
  301.  
  302.     вернись к
  303.     http://enterprisecraftsmanship.com/2016/09/29/law-of-demeter-and-immutability/
  304.     http://enterprisecraftsmanship.com/2016/05/12/immutable-architecture/
  305. */
  306. ********************************************
  307.         public PreConditionsBuilder tasks(TaskType taskType, String... taskNames) {
  308.         /*
  309.             при такой реализации метода - не получишь цепочки тасок
  310.              закомпличеная а
  311.              активная b
  312.              закомпличеная с
  313.  
  314.             а это - серьезное ограничение
  315.             особенно - с учетом уровня сложности
  316.             который используется в реализации
  317.  
  318.             да и  switch  - не знаю
  319.             мне кажется - решение было бы аккуратнее внутри и проще снаружи
  320.             если бы мы могли вызывать
  321.             ...comlpeledTasks("a", "b").activeTasks("c", "d").completedTasks("e", "f")
  322.             и получать таски - в нужном нам состоянии и именно в такой последовательности
  323.  
  324.             т е - снаружи - у каждого вызываемого метода - предельно простые параметры - тексты тасок
  325.             и   - изнутри - каждый из методов не оперирует никакими switch
  326.             да и в таком случае - от юзера - вообще можно спрятать  TaskType
  327.             этот тип будет лишь для внутреннего пользования
  328.         */
  329. *********************************
  330. public PreConditionsBuilder filter(FilterType filterType) {
  331. /*
  332.     лучше - 3 метода без параметра
  333.     чем один с параметром)
  334.  
  335.     будь KISS )
  336.     https://docs.google.com/document/d/13dNyFGbI7mV22UUhH8E0LJ7SzabAmX7Bw7VCHScYfiU/edit#bookmark=id.8bflixemdgfw
  337. */
  338. *******************************************************
  339.     private void openFilterPage()
  340. /*
  341.     тут вместо switch -
  342.     можно было бы заюзать
  343.  
  344.     open(filterType.getUrl())
  345.     если бы FilterType - такой метод имел
  346.  
  347.     см пример ниже
  348.     советую именно так реализовать
  349.  
  350.     и я советую назвать enum не FilterType
  351.     а просто - Filter
  352.     мы ничего из важного - не потеряем
  353. */
  354. public enum Day {
  355.         MONDAY("понедельник"),
  356.         TUESDAY("вторник"),
  357.         WEDNESDAY("среда"),
  358.         THURSDAY("четверг"),//<<----------------------для каждого значения enum - вызов конструктора, фактически значение = объект класса
  359.         FRIDAY("пятница"),
  360.         SATURDAY("суббота"),
  361.         SUNDAY("воскресенье");
  362.  
  363.         String description;//<<---------------------------поле для хранения описания дня недели
  364.  
  365.         public Day(String description) {
  366.                 this.description = description;//<<---------------------------логика конструктора - запомнить для объекта его описание
  367.         }
  368.  
  369.         @Override
  370.         public String toString() {
  371.             return description;//<<---------------------------логика - вывести для объекта - то что для него заполнили
  372.         }
  373. }
  374. *******************************************************************
  375.         public void buildPreConditions() {
  376.             openFilterPage();
  377.             clearLocalStorage();
  378.             /*
  379.                 локалсторидж чистить не нужно
  380.                 ведь далее - присваивается заново - значение его итему
  381.                 который отвечает за список тасок
  382.                 этого хватит с головой
  383.  
  384.                 да и - раз так - то и в афтер-методе - не нужно ничего чистить
  385.                 если принять - что в каждом тест-методе - мы будем готовить тестовую ситуацию с помощью гивен-методов
  386.  
  387.                 и выше - уже есть код который обеспечивает открытие урла
  388.                 значит - и бифор метод для открытия урла - не нужен
  389.                 значит - и класс OpenTodoMVCAndClearData - в целом не нужен
  390.                 убирай его из проекта
  391.  
  392.                 еще насчет openFilterPage();
  393.                 можно реализовать ensureopenFilterPage();
  394.                 в нем - проверяем
  395.                 если у нас уже нужный урл
  396.                 то и ничего не надо открывать
  397.             */
  398.             addTasksToLocalStorage();
  399.             getWebDriver().navigate().refresh();
  400.             /*
  401.                 рефреш кстати - не всегда помогает - если работать вот так с фильтрами
  402.                 возможно - тебе понадобится выполнение JavaScript команды location.reload()
  403.                 вместо рефреша (см выше - его можно выполнить проще)
  404.                 http://www.w3schools.com/jsref/met_loc_reload.asp
  405.             */
  406. ********************************************
  407.         private void addTasksToLocalStorage() {
  408. /*
  409.     тут - только вопрос - который уже выше озвучивала
  410.     как нам задать таски а разных статусах - идущие вразнобой - одна такая, следующая другая и т д
  411. */
  412. *************************
  413. public class SmokeTodoMVCTest
  414. /*
  415.     объединять тесты для Smoke покрытия в одном тест-классе - не свегда удачная идея
  416.     часто - удобнее - когда тесты собраны по тест-классам тематически
  417.     и некоторые из них - составляют смоук покрытие
  418.     это скоро научимся делать
  419.  
  420.     так что - да  - важное заметил - нам надо уметь запускать только тесты для такого-то покрытия
  421.     но реализовывать это нужно по-другому
  422.  
  423.     этот тест-класс - оставь как тест-класс для интеграционных тестов
  424.     фиче-тесты - расположи в соответствующих фильтру тест-классах
  425.  
  426.     в каждом тест-методе - используй гивен-методы
  427.  
  428.     хм....
  429.     смотрю на другие тест-классы - похоже ты так и сделал
  430.     а это - с прошлого задания тест-класс
  431.  
  432.     если так - все равно переименуй тест-класс в TodoMVCTest
  433.     и расположи в правильном пекедже - где ты предыдущие задания собираешь
  434.     как для предыдущего задания - с ним все ок
  435. */
  436. ****************************************
  437. //сравни
  438.    givenAtTodoMvc()
  439.                 .tasks(TaskType.COMPLETED, "compl1")
  440.                 .filter(FilterType.ALL)
  441.                 .buildPreConditions();
  442. //или
  443.    given()
  444.         .completedTasks("compl1")
  445.         .atAllFilter()
  446.         .build();
  447. //или даже вот так
  448.    givenTasks()
  449.         .completed("compl1")
  450.         .atAll()
  451.         .build();
  452. /*
  453.     упрости сигнатуру у методов
  454.     для фильтров - проще оперировать тремя методами без параметров, а не одним с параметром
  455.     для тасок - проще оперировать двумя методами с просыми параметрами - чем еще  одним параметром - типом таски
  456.  
  457.     в результате - того кто пишет тест-методы -
  458.     вообще не будет волновать существование типов  - для типа таски или фильтра
  459.     все это будет под капотом
  460.  
  461.     поскольку мы работаем с TodoMvc и это сказано в имени тест-классов
  462.     уже тут - AtTodoMvc - не нужно писать
  463.     givens и preconditions - синонимы
  464.     потому - начни с given() и заканчивая - уже не надо писать про PreConditions
  465.  
  466.     наверное - мой первій предложенный вариант - наименее радикальный)
  467.     второй - порадикальнее)
  468.     какой ты выберешь - дело твое)
  469.  
  470.     но - подупростить и подсократить надо бы)
  471. */
  472. *************************************
  473.     @Test
  474.     public void clearCompleted() {
  475.         givenAtTodoMvc()
  476.                 .tasks(TaskType.ACTIVE, "1")
  477.                 .tasks(TaskType.COMPLETED, "compl2")
  478.                 .filter(FilterType.ACTIVE)
  479.                 .buildPreConditions();
  480.  
  481.         page.clearCompleted();
  482.         // TODO how to check it with existing functional ?
  483.     }
  484. /*
  485.     проверь тексты тасок и итемс лефт
  486.  
  487.     этого будет достаточно
  488.  
  489.     уже разбирали в слеке -
  490.     у нас же должен быть тест - когда мы с какого-то фильтра переключаемся на эктив
  491.     и в списке - у нас видимы только активные таски + итемс лефт - именно их и отражает
  492.     (по-моему - не все 6 переходов с фильтра на фильтр покрыты тестами - это высокоприоритетное
  493.     с комплитеда на эктив - нету вроде бы)
  494.  
  495.     в нашем случае - количество видимых тасок в списке (мы проверили тексты)
  496.     равно количеству итемс лефт (мы проверили итемс лефт)
  497.     косвенно - мы можем сделать вывод - что все ок - если эти 2 проверки прошли
  498.  
  499.     если не нравится идея
  500.     можно монизить приоритет clearCompleted на эктив фильтре до среднего и не покрывать
  501.  
  502.     или - придумать - как реализовать маленький е2е
  503.     в котором что-то еще проверить
  504.     и уточнить то - что нам нужно
  505.  
  506.     я за первый вариант
  507.  
  508.     то же касается и других твоих похожих вопросов (то что ты оранжевым в тест-плане выделил)
  509.  
  510. */
  511. ************************************************************************
  512. ==================================================================================================
  513. 1. "    @After
  514.        public void afterMethod() {
  515.            clearLS();
  516.            getWebDriver().navigate().refresh();
  517.        }
  518.    /*
  519.        спорно - стоило ли выносить в отельный метод clearLS() - очистку локалсториджа
  520.        да еще и в имени метода - сокращать слова"
  521.  
  522.             >>>>>>>> ну по поводу отдельного метода, разве мы не стараемся сделать наши тесты
  523.                     как можно более простыми и читабельными? а @Before и @After это же часть
  524.                     тестов, в них тоже описана тестовая логика (pre-conditions, post-conditions),
  525.                     почему мы в тесты стараемся писать чуть ли не человеко-понятный текст, а в
  526.                     бифор и афтер прямо какие то JS комманды? это из серии переменные создавать
  527.                     тогда, когда ты переиспользуешь значение в нескольких местах, или когда их
  528.                     можно описать простым и понятным языком) вместо тех. деталей)
  529.  
  530.                     по поводу сокращения - возможно неправ, можно было написать полностью, мы просто
  531.                     в рабочем проекте плотно работаем с ЛС, и эта аббревиатура как то прижилась
  532.                     и всем понятна, привычка)
  533. /*
  534.     так тут  - одна строчка )
  535.     причем - очень похожая на clearLocalStorage )
  536.     если б там были километры кода - да, надо было бы спрятать
  537.     а так - имхо, перебор
  538.  
  539.     в нескольких местах - этот метод не использовался
  540.     а теперь и вовсе не будет нужен) - с появлением гивенов
  541.  
  542.     аббревиатура - да
  543.     от проекта к проекту - допускаю - что какая-то приживается
  544.     но общее правило - новую не придумывай)
  545.     юзай только стандартную
  546. */
  547. ==================================================================================================
  548. 2. "насчет рефреша
  549.    в selenide - есть метод refresh()
  550.    технически - то же самое
  551.    просто лаконичнее"
  552.  
  553.             >>>>>>>> видел метод, пробовал. он инкапсулирует в себе open(), который у меня на
  554.                     selenide 3.11 & ff 47.0.1 не работает (не перегружает страницу), поэтому вручную
  555.                     вызвал рефреш у драйвера
  556.  
  557.                     и по методу open() в пейдже тоже страница не перегружается
  558. /*
  559.     ясно
  560.  
  561.     я писала выше - тут вообще стоит location.reload() делать
  562.     после таких открытий - сразу на урле фильтра
  563.     как показал опыт - самое надежное решение
  564. */
  565. ==================================================================================================
  566. 3. "    идеально наверное, вообще вот так -
  567.        page.itemsLeft().shouldBe(...)
  568.  
  569.        ну то потом так напишем)
  570.  
  571.        щас - не буду спорить"
  572.  
  573.             >>>>>>>> я не силен в ООП в джаве пока, ума хватило только на такую реализацию.
  574.                     посмотри пожалуйста, так нормально реализовано?
  575. /*
  576.     все ок в общем-то
  577.     стоило ли делать иннер-классом - а не знаю)
  578.     может в данном случае и стоило)
  579.  
  580.     оставляй
  581.     молодец)
  582. */
  583. ==================================================================================================
  584. 4. "ну и варианты тут есть для additional edit operations
  585.    confirmEditByPressTab
  586.    confirmEditByClickOutside
  587.    deleteByEmptyingText"
  588.  
  589.         >>>>>>>> пока исправил editEnter на edit (раз мы считаем это дефолтной ситуацией)
  590.                 могу попробовать сделать что то типа
  591.  
  592.                 page.edit("1", "edited1").confirmEnter();
  593.                 page.edit("1", "notedited1").discardEsc();
  594.  
  595.                 нужно?
  596. /*
  597.     то уже перебор
  598.     имхо)
  599.  
  600.     виджеты - будем разбирать отдельно
  601.     и не на таком примитиве как тудуэмвиси - тут действительно примеры из пальца высасываем)
  602. */
  603. ==================================================================================================
  604. 5. "
  605.    проверяя - $("#todo-count>strong").shouldHave(exactText(...
  606.    мы косвенно проверяем - что футер видим
  607.  
  608.    а вот стоит ли проверять - что футер не видим....
  609.    я б не стала
  610.    в виду невысокого приоритета такой фичи
  611. "
  612.  
  613.         >>>>>>>> я имею ввиду если например есть 1 закомпличенная задача и 0 активных - футер есть,
  614.                 и в нем нужно проверять itemsCount - 0, а если нет вообще задач - то и футера нет,
  615.                 и не надо ничего в нем искать, можно взамен проверить что он невидим
  616. /*
  617.     я поняла твою идею
  618.  
  619.     лучше - быть точным
  620.     если хотим проверить - что футера нет - знач надо именно это и проверять
  621.  
  622.     а не прятать внутри проверки итемс лефта варианты
  623.     перечитай прошлый пассаж
  624.  
  625.     он про то - что не надо прятать внутри вспомогательных методов какую-то тестовую логику
  626. */
  627. ===================================================================================================
  628. 6. "https://www.youtube.com/watch?v=w_rPX9TwDkA
  629. http://spirogov.github.io/video-recorder-intieghratsiia-s-jenkins-i-allure-rieportami/"
  630.  
  631.         >>>>>>>> попробовал, но чет у меня нормально не получилось, я не совсем понимаю
  632.                 чем отличается @Rule от @Before, и как с ними работать, и у меня он постоянно
  633.                 падал на методе
  634.  
  635.                 @Attachment(value = "video", type = "video/mp4")
  636.                     private byte[] attachment() throws InterruptedException {
  637.                         try {
  638.                             File video = VideoRecorder.getLastRecording();
  639.                             await().atMost(5, TimeUnit.SECONDS)
  640.                                     .pollDelay(1, TimeUnit.SECONDS)
  641.                                     .ignoreExceptions()
  642.                                     .until(() -> video != null);
  643.  
  644.                             return Files.readAllBytes(Paths.get(video.getAbsolutePath()));
  645.                         } catch (IOException e) {
  646.                             log.warning("Allure listener exception" + e);
  647.                             return new byte[0];
  648.                         }
  649.                     }
  650.  
  651.                 на await(). и видео перекошенное писалось, еще и видео перекошено, жуть кароче)
  652.  
  653.                 на этом моменте писал тут вопрос по поводу где почитать за JUnit, а как дошел до
  654.                 след пункта как раз ты дала офигенную статью, спасибо! стало намного понятней,
  655.                 зачем нужны все эти рулы, бифоры, и чем они друг от друга отличаются)
  656.  
  657.                 я так понял, что по идеологии JUnit "дешевые ресурсы" должны создаватся\удалятся
  658.                 в @Before and @After, дорогие в @BeforeClass, @AfterClass, а что то обобщенное,
  659.                 в зависимости от места где нужно это в @Rule and @ClassRule.
  660.  
  661.                 только теперь у меня такой вопрос, разве скриншоты\видео не то самое, глобальное,
  662.                 что нужно делать всегда? почему бы тогда не вынести в @Rule PublishScreenAllure
  663. /*
  664.     рада, что статья понравилась)
  665.     еще что-то было про перекошенность видео и аллюр-репорты
  666.     http://spirogov.github.io/video-recorder-intieghratsiia-s-jenkins-i-allure-rieportami/
  667.     может, не давала линку
  668.     там есть про эти моменты
  669.     честно говоря - я сапожник без сапог - руки не доходят поиграться как следует)
  670.    
  671.     когда удалять-создавать - я решаю исходя из целей и обстоятельств
  672.     если что-то можно сделать разово - перед запуском всех тестов - так почему нет)
  673.    
  674.     рулы - разумно использовать - когда тебе недостаточно бифоров-афтеров
  675.     типа - надо обработать отдельно - ситуацию с фейлом, например
  676.     я - сторонник простых решений)
  677.     если можно делать просто - надо делать просто)
  678.    
  679.     насчет - надо делать всегда - про скриншоты - не знаю)
  680.     не для всех проектов это так)
  681.     и для простого случая - когда нужен лишь скриншот на конец каждого теста - афтер метод куда проще)
  682.     и это - можно объяснить и новичку
  683.     если это цель - то афтер-метод лучше)
  684.    
  685.     хотя - с рулой - можно избавиться от предка тест-класса вообще
  686.     что тоже приятный бонус)
  687.     может и красивее такое в рулу спрятать, соглашусь с тобой    
  688. */
  689. *********************************************************
  690.  
  691.                 public class BaseTest {
  692.  
  693.                     public final static String ROOT_REPORT = "target" + separator + "site" + separator + "allure-maven-plugin" + separator;
  694.  
  695.                     @Rule
  696.                     public ExternalResource resource = new PublishScreenAllure();
  697.  
  698.                     @BeforeClass
  699.                     public static void baseBeforeClass() {
  700.                         Configuration.browser = "firefox";
  701.                     }
  702.  
  703.  
  704.                     static class PublishScreenAllure extends ExternalResource {
  705.  
  706.                         PublishScreenAllure() {
  707.                             Configuration.screenshots = false;
  708.                             Configuration.reportsFolder = ROOT_REPORT + "screenshots";
  709.                         }
  710.  
  711.                         @Override
  712.                         protected void after() {
  713.                         }
  714.  
  715.                         @Override
  716.                         protected void before() throws Throwable {
  717.                             publishScreenshot();
  718.                         }
  719.  
  720.                         @Attachment(value = "Page-screenshot", type = "image/png")
  721.                         protected byte[] publishScreenshot() {
  722.                             File screenshot = Screenshots.takeScreenShotAsFile();
  723.                             try {
  724.                                 return readAllBytes(Paths.get(screenshot.toURI()));
  725.                             } catch (IOException | NullPointerException e) {
  726.                                 System.err.println("Exception occurred while trying to read from screenshot file." +
  727.                                         "\n cause: " + e.getCause());
  728.                                 return new byte[0];
  729.                             }
  730.                         }
  731.  
  732.                     }
  733.                 }
  734.  
  735.                 получится что скриншоты для аллюра это просто типа как сервис, хош включай, не хош не включай
  736. /*
  737.     а вот внутрь предка тест-класса - впихивать реализацию рулы - не надо)
  738.     отдельный класс
  739.     и просто юзай для тест-классов - уже вообще предок не нужен
  740.    
  741.     пара строк - на создание рулы
  742.     одна - на создание пейджа
  743.     не думаю - что ради такого стоит городить предка для тест-класса    
  744.    
  745.     папки переназначать или фф прописывать - я б на стала)
  746. */                
  747. ===================================================================================================
  748. 7. вопрос по скринам селенида.
  749.     получается есть флаг
  750.  
  751.     Configuration.screenshots = true;
  752.  
  753.     который вроде как означает что мол делай скрины если тест упал - ок.
  754.     если я хочу не только когда упал, а всегда, то надо пользоватся
  755.  
  756.     @Rule
  757.     public ScreenShooter makeScreenshotOnFailure = ScreenShooter.failedTests().succeededTests();
  758.  
  759.     но рулы исполняются до @Before и после @After, т.е. даже если я включу на успешных тестах скрины,
  760.     в своем @After я его не увижу.
  761.  
  762.     теперь вопрос, можно ли не переопределяя селенидовский рул, сделать нормальные скриншоты
  763.     (чтоб были их списки, то да се, всякие удобные селенидовские штуки) ?
  764.  
  765.     пока варианта у меня 2 (не геморных):
  766.  
  767.     1 - publishScreenshot() из BaseTest (плюсы - просто относительно, минусы - при fail дублируются
  768.         скрины, создается в Users/user/....)
  769.     2 - AllureScreenPublisher.class в api (плюсы - скриншоты не дублируются, создаются в проекте в
  770.         соотв. папочке, после того как скрин отправлен аллюру - чистятся (мы их потом смотреть не
  771.         будем руками, они в аллюре уже сохранены), минусы - хз, попахивает костылем, но пока вроде
  772.         работает))
  773. /*
  774.     нормально подрубиться к ScreenShooter - не выйдет)
  775.     причину - ты хорошо описал)
  776.     возможно - можно отнаследоваться от ScreenShooter
  777.     и что-то там дописать в потомке
  778.     но я не вижу острой необходимости так делать
  779.    
  780.     твои 2 варианта - ок
  781.     насчет не чистятся - я писала про это
  782.     костыля - не вижу
  783.     особенно - если код немного поравнять)
  784. */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement