julia_v_iluhina

Untitled

Jan 17th, 2017
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 18.81 KB | None | 0 0
  1. ревью на
  2. sources (review 9 + new task 10 + new task 11) - https://github.com/AleksanderPopov/automician_course/tree/master/src/
  3.     изменения после 9 реью, сделал pageObject pageModule, добавил тесты для google
  4.  
  5. http://joxi.ru/Dr860ybh4oqdQ2
  6. /*
  7.     исходя из того - что такие классы могут беть переиспользованы не только для todoMVC - разумно вынести это по структуре выше
  8.     в пекедж core (или api)
  9.  
  10.     GivenHelpers - в пекедже given или helpers
  11.     что-то более близкое по смыслу
  12.     точно не api это
  13. */
  14. ***********************************
  15. public class AllureHelper {
  16.  
  17.     @Attachment(value = "Page-screenshot", type = "image/png")
  18.     public static byte[] publishScreenshot() {
  19.         String path = getPathOf(screenshot());
  20.         ...
  21.     }
  22.  
  23.     @Attachment(value = "Page-source", type = "text/html")
  24.     public static byte[] publishHtml() {
  25.         String path = getPathOf(screenshot());
  26.         ...
  27. /*
  28.     тут можно чуть оптимальнее
  29.  
  30.     если нам нужно приаттачить и скриншот, и html
  31.     то получится - что мы дважды вызываем screenshot()
  32.  
  33.     помимо того что это не оптимально
  34.     еще может быть вот что
  35.     вызвали publishScreenshot() - зафиксили скриншот
  36.     ситуация успела поменяться
  37.     потом вызываем publishHtml() - получаем  html, который к только что приаттаченному скриншоту - никакого отношения не имеет
  38.     можно долго разбираться в таких дебрях)
  39.  
  40.     было бы круто - если бы мы могли как-то вот так вызывать AllureHelper
  41.  
  42.     allureAttachment().withScreenshot().withHtml().build().publish() (тут без билдер-паттерна тоже не обойдешься ))
  43.  
  44.     ну или вариант попроще - метод с параметрами - что формировать
  45.     мне меньше нравится - т к при вызове будет замудренее
  46.  
  47.     и дальше это можно использовать
  48.     @Rule
  49.     public Publisher publisher = Publisher.always().withAttachments(allureAttachment().withScreenshot().withHtml().build()).createPublisher();
  50.  
  51.     т е - вообще отвязать логику формирования аттачментов
  52.     от логики работы правила
  53.     правило - лишь диктует - когда что делать
  54.  
  55.     а что делать - будет определяться переданным объектом
  56.  
  57.     (этот параметр - параметр метода withAttachments - лучше сделать более абстрактного типа - типа
  58.         interface AttachmentHelper
  59.         с объявленными методами
  60.             publish();
  61.             clean(); (это если захочешь - я по-прежнему считаю - что это лишнее)
  62.     )
  63.     а AllureHelper - пусть имплементирует AttachmentHelper
  64.  
  65.     будет выполняться Single Responsibility Principle)
  66.     получится крутое решение)
  67.     оно и сейчас уже огого )
  68. */
  69. ***************************************
  70.  private void addTasksToLocalStorage() {
  71.         StringBuilder tasksJson = new StringBuilder("");
  72.         tasksJson.append(doJsonfromList(true, activeTasks))
  73.                 .append(tasksJson.toString().isEmpty() ? "" : ",")
  74.                 .append(doJsonfromList(false, completedTasks));
  75. /*
  76.     вот - видишь
  77.     получаем - всегда будут идти вначале - активные таски
  78.     потом - закомпличеные
  79.     как бы мы их не добавляли сами - картинка будет только такая
  80.  
  81.     а надо - как добавляли
  82.     чтоб в такой последовательности они и шли
  83.  
  84.     потому - нужно чтоб еще на этапе сборки списка тасок - ты оперировал не двумя списками отдеьными для активных и закомпличеных
  85.     а одним списком
  86.     тогда такой проблемы не будет
  87.  
  88.     правда - списком строк уже не обойдешься в таком случае
  89.  
  90.     заодно и код метода
  91.     private Builder tasks(TaskType taskType, String... taskNames) {
  92.     улучшится )
  93.  
  94.     я не сторонник применения switch (taskType)
  95.     чаще всего без него можно обойтись, причем более простой логикой
  96.     даже при такой как сейчас реализации - метод tasks просто лишний
  97.  
  98.     сравни
  99.         Collections.addAll(activeTasks, taskNames);
  100.         return this;
  101.     и
  102.         return tasks(TaskType.ACTIVE, taskNames);
  103.  
  104.     С учетом того - что вообще уйдет tasks - первый вариант мне кажется лучшим решением)
  105. */
  106. ***************************************
  107. public enum Filter {
  108. /*
  109.     его пабликом делать ни к чему
  110.     все внутри гивен хелпера ведь происходит
  111.  
  112.     а снаружи - просто вызываем соотвествующий метод
  113.     не надо нам видеть сложное снаружи)
  114.  
  115.     пусть снаружи - будет просто
  116. */
  117. ********************************
  118.     public enum Filter {
  119.         ALL(""),
  120.         ACTIVE("active"),
  121.         COMPLETED("completed");
  122.  
  123.         private String subUrl;
  124.  
  125.         Filter(String subUrl) {
  126.             this.subUrl = subUrl;
  127.         }
  128.  
  129.         @Override
  130.         public String toString() { return "https://todomvc4tasj.herokuapp.com/#/" + this.subUrl; }
  131.     }
  132. /*
  133.     чуть более DRY вариант предлагаю
  134.  
  135.     не настаиваю - т к твой вариант более KISS )
  136.     а это тоже важно)
  137.  
  138.     лично для себя я держу такую грань
  139.     то что юзаю в тест-методах - должно быть более KISS
  140.     а вот сама реализация пейджей/виджетов/хелперов/кондишенов - тут уже просто правила разработки ПО применяю
  141.     DRY - тут уже важно )
  142.     т е - снаружи все эти  пейджи/виджеты/хелперы/кондишены = то что видно при использовании этого всего
  143.     должно конечно обеспечивать KISS
  144.     а вот внутри - там где мы алгоритмы реализуем, какую-то сравнительно серьезную логику - там уже значимость DRY - гораздо выше
  145.  
  146.     потому бы - для enum Filter
  147.     выбрала более DRY реализацию
  148. */
  149. ****************************
  150.     private void openFilterPage() {
  151.         switch (this.filter) {
  152.             case ALL: {
  153.                 open(ALL.url);
  154.                 break;
  155.             }
  156.             case ACTIVE: {
  157.                 open(ACTIVE.url);
  158.                 break;
  159.             }
  160.             case COMPLETED: {
  161.                 open(COMPLETED.url);
  162.                 break;
  163.             }
  164.             default:
  165.                 throw new UnsupportedOperationException("Wrong FilterType parameter");
  166.         }
  167.     }
  168. //сравни
  169.     private void openFilterPage() {
  170.         open(this.filter.toString())
  171.     }
  172. /*
  173.     тут тоже без switch - вполне ок будет
  174. */
  175. ***************************************
  176.  return tasks.findBy(cssClass("editing"))
  177.                 .find(" .edit")
  178. /*
  179.     тут - пробел перед  .edit не дает ровно ничего
  180.  
  181.     метод find для SelenideElement - ищет строго внутренние элементы
  182.     согласно цсс селектору = маске
  183.  
  184.     так что от этого пробела - ни холодно, ни жарко
  185.  
  186.     хотя в цсс селекторе этом - ты вообще можешь прописать и какой-то кусок
  187.     который относится и к чему-то внешнему
  188.     такое извращение надо - если хочется наложить фильтр дополнительный
  189.  
  190.     не по теме этого задания
  191.     просто на тему  find для SelenideElement и findElement для WebElement селениумского
  192.     (тут логика один-в-один)
  193.     http://pastebin.com/TivB2FzA
  194. */
  195. ************************
  196. public class SmokeTodoMVCTest extends BaseTest {
  197. /*
  198.     уже в вопросах-ответах - обсудили
  199.     не делаем тест-классы для такого-то покрытия
  200.  
  201.     в тест-классах - собираем тест-методы по другому принципу - что мы тестируем
  202.     какой аспект нашего приложения
  203.  
  204.     а покрытие - категориями обозначаем и так обеспечиваем запуск нужных нам тестов
  205. */
  206. ********************************
  207.     @Test
  208.     public void basicTasksFlow() {
  209.     /*
  210.         перемудрил малость ты с тестом)
  211.     */
  212.         given().completed("compl1")
  213.                 .atAllFilter()
  214.                 .prepare();
  215.  
  216.         add("2");
  217.         /*
  218.             в этот момент = у тебя 2 таски в списке
  219.             значит - операция edit("2"
  220.             не проверит результат предыдущей операции add("2");
  221.             т к проверит состояние только одной из 2-ух тасок
  222.  
  223.             не торопись добавлять таску
  224.             ты ж можешь и compl1 отредактировать
  225.  
  226.             кстати - не советую так таску называть)
  227.             вот это - активная или закомпличеная - очень легко меняется в процессе
  228.             и выносить это в имя таски - имхо - перебор
  229.  
  230.             и еще - не сокращай слова
  231.             если сокращение не общепринятое - не используй его
  232.         */
  233.         edit("2", "edited2");
  234.         shouldHave("compl1", "edited2");
  235.  
  236.         goActive();
  237.         /*
  238.             следующее действие - лишь проверит что "edited2" - есть
  239.             а состояние всего списка - не проверено
  240.  
  241.             я б только тут добавляла вторую таску
  242.             после проверки состояния списка
  243.         */
  244.         cancelEdit("edited2", "notedited2");
  245.         toggle("edited2");
  246.         /*
  247.             проверка?
  248.             идем по кругу)
  249.         */
  250.  
  251.         goCompleted();
  252.         /*
  253.             проверка нужна
  254.         */
  255.         destroy("edited2");
  256.         shouldHave("compl1");
  257.         /*
  258.             как-то без имени пейджа - shouldHave("compl1") - по-сиротски выглядит)
  259.             не понятно - кто это кому должен)
  260.             читай чуть ниже
  261.         */
  262.         toggle("compl1");
  263.         /*
  264.             нужна проверка
  265.             эххх)
  266.         */
  267.  
  268.         goAll();
  269.         shouldHave("compl1");
  270.     }
  271.  ***************************************
  272. public class TaskPage {
  273. /*
  274.     если юзаешь пейдж-модуль
  275.     то в имени пейджа - уже не надо Page указывать
  276.  
  277.         Пейдж-модули удобно называть без слова Page в конце
  278.             потому что если ты будешь использовать несколько пейдж-модулей в одном тесте
  279.  
  280.             то желательно обращаться к их методам через имя класса пейдж-модуля
  281.             чтобы видеть где с каким пейджом идет работа
  282.  
  283.             и когда ты будешь писать
  284.                 TodoMVCPage.givenAtAll()
  285.             то это явно не так прикольно как
  286.                 TodoMVC.givenAtAll()
  287.  
  288.             правда?
  289.  
  290.                 (так обращаться - важно, когда есть несколько пейджей,
  291.                 а если он один - то можно без ущерба для точности -
  292.                 заимпортить статически все методы и при вызове - не указывать им класса пейдж-модуля)
  293.  
  294.  
  295.             вот это Page в конце - это дань общим conventions (или общепринятым предпочтениям)
  296.             при именовании классов в мире ООП
  297.  
  298.             ми же тут юзаем подход "Модульного Программирования", потому тут этого "лишнего слова"
  299.             не нужно
  300.  
  301.             А то, что это все же пейдж - скажет нам имя пекеджа - pages
  302.  
  303.     кстати - Tasks.shouldHave("compl1") - уже ниче так) попонятнее)
  304.     а если не хочешь явно указывать для методов пейджа - имя его класса Tasks
  305.     то тогда лучше для проверок используй имена assert....
  306.     так оно логичнее будет
  307.  
  308.     учти - еесли будешь указывать имя пейджа-модуля
  309.     то это надо делать всегда
  310.     а не через раз
  311.     иначе путать будет
  312. */
  313. ***************************
  314.     @Step
  315.     public static ItemsLeft itemsLeft() {
  316.         return new ItemsLeft();
  317.     }
  318.  
  319.     public static class ItemsLeft {
  320.         private static final SelenideElement element = $("#todo-count>strong");
  321.  
  322.         public void shouldBe(int itemsCount) {
  323.             element.shouldHave(exactText(String.valueOf(itemsCount)));
  324.         }
  325.     }
  326. /*
  327.     для подхода с пейджами-модулями
  328.     я бы продолжила и тут тему
  329.  
  330.     Tasks.ItemsLeft.shouldBe...
  331.  
  332.     т е - от метода itemsLeft() - избавилась бы)
  333.  
  334.     раз пейджи-модули - знач пейджи-модули)
  335.     никаких объектов)
  336. */
  337. **********************************
  338.     @Test
  339.     public void delete() {
  340.         given().active("1", "2")
  341.                 .atActiveFilter()
  342.                 .prepare();
  343.  
  344.         destroy("1");
  345.         shouldHave("2");
  346.         itemsLeft().shouldBe(1);
  347.     }
  348. /*
  349.     тут delete() , там destroy() - не
  350.     так не надо
  351.     одно понятие = один термин
  352.     нужна однозначность
  353.  
  354.     кстати, вызовы Tasks.... решили бы проблему
  355.     см ниже вариант
  356. */
  357.     @Test
  358.     public void delete() {
  359.         given().active("1", "2")
  360.                 .atActiveFilter()
  361.                 .prepare();
  362.  
  363.         Tasks.delete("1");
  364.         Tasks.shouldHave("2");
  365.         Tasks.ItemsLeft.shouldBe(1);
  366.     }
  367. *****************************
  368. /*
  369.     то же касается и других тест-методов
  370.  
  371.     в их названиях ті используешь какие-то новые термины
  372.     не такие - какие использовал на уровне имено вспомогательных методов
  373.  
  374.     это надо поправить
  375.  
  376.     однозначный код - всегда лучше
  377. */
  378. ****************************
  379. public class TasksOperationsAtCompleteFilterTest extends BaseTest {
  380.  
  381.     @Test
  382.     public void editConfirmEnter() {
  383.         given().completed("1", "2")
  384.                 .atCompletedFilter()
  385.                 .prepare();
  386.  
  387.         edit("1", "2");
  388.         shouldHave("2", "2");
  389.     }
  390.    
  391. public class TasksOperationsAtActiveFilterTest extends BaseTest {
  392.  
  393.     @Test
  394.     public void editConfirmedByEnter() {
  395.         given().active("1", "2")
  396.                 .atActiveFilter()
  397.                 .prepare();
  398.  
  399.         editEnter("2", "edited2");
  400.         shouldHave("1", "edited2");
  401.     }    
  402. /*
  403.     сравни имена вспомогательных методов
  404.     имена тест-методов
  405.    
  406.     разброд и шатания)
  407.    
  408.     итемс лефт - проверяй в фиче-тестах всегда
  409.     если это возможно
  410. */
  411. ***********************************
  412.  
  413.     @Test
  414.     public void addTask() {
  415. /*
  416.     еще пример разброда - то применяешь Task в имени тест-метода
  417.     то нет
  418.    
  419.     определись
  420.     и делай одинаково
  421. */
  422. ***************************************
  423.     public class TasksOperationsAtAllFilterTest extends BaseTest {
  424.  
  425.         @Test
  426.         public void editConfirmByClickOutside() {
  427.             given().active("1", "2")
  428.                     .atAllFilter()
  429.                     .prepare();
  430.  
  431.             editTab("1", "2");
  432.             shouldHave("2", "2");
  433.             itemsLeft().shouldBe(2);
  434.         }
  435. /*
  436.     в имени тест-метода - написано одно
  437.     а делаешь - другое
  438.    
  439.     к следующему разу
  440.     с именами утряси все
  441.     просмотри - чтоб в методах делалось то что заявлено в имени тест-метода
  442.     чтоб проверок хватало
  443.     чтоб тестовые ситуации ииспользовал разнообразные
  444.     чтоб с покрытием было все ок
  445.    
  446.     используй тест-план
  447.    
  448.     самая скучная часть работы)
  449.     но - это важные детали)
  450.     так что придираться буду    
  451. */
Advertisement
Add Comment
Please, Sign In to add comment