julia_v_iluhina

Untitled

Jul 29th, 2016
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 19.44 KB | None | 0 0
  1. *******************************************
  2. /*
  3.     Для первой версии этого задания - очень прилично)
  4.     сначала разберемся с гивенами)
  5. */
  6.  
  7. *******************************************
  8.  
  9. public class Task
  10. /*
  11.     Этот класс можно было в рамках этого задания - объявить внутри тест-класса
  12.     Т к только там он используется, и т к в этом задании мы еще не ставили себе цели -
  13.     отделить вспомогательные методы от тест-класса
  14.     Эту задачу - будем решать в следующих работах
  15.  
  16.     Пока объяви класс Task внутри самого тест-класса
  17.     Иначе - уже сейчас придется обсуждать - как лучше вынести вспомогательное из тест-класса
  18.     Давай этот момент отложим - и так много чего в этом задании надо сделать
  19. */
  20.  
  21. ********************************************
  22.  
  23.  @Step
  24.     private void given (Task... tasks){
  25.         String setItem = "localStorage.setItem(\"todos-troopjs\", ";
  26.         String startOfTaskArray = "\"[";
  27.         String endOfTaskArray = "]\")" ;
  28.         String taskList = "";
  29.  
  30.         for (int i = 0; i < tasks.length; i ++){
  31.             if (i != tasks.length - 1){
  32.                 taskList += tasks[i].getTaskStatus() + "\\\"title\\\":\\\"" + tasks[i].getName() + "\\\"}, ";
  33.             }
  34.             else {
  35.                 taskList += tasks[i].getTaskStatus() + "\\\"title\\\":\\\"" + tasks[i].getName() + "\\\"}";
  36.             }
  37.         }
  38.  
  39.         executeJavaScript(setItem + startOfTaskArray + taskList + endOfTaskArray);
  40.         refresh();
  41.     }
  42.  
  43. /*
  44.     сравни строки
  45.     executeJavaScript(setItem + startOfTaskArray + taskList + endOfTaskArray);
  46.     и
  47.     executeJavaScript("localStorage.setItem(\"todos-troopjs\", " + "\"[" + taskList + "]\")");
  48.  
  49.     получилось - не намного длиннее, не менее DRY, и намного проще
  50.     избавься от этих трех переменных, они только необоснованно усложняют код
  51.  
  52.     дальше сравниваем
  53.     taskList += tasks[i].getTaskStatus() + "\\\"title\\\":\\\"" + tasks[i].getName() + "\\\"}, ";
  54.     и
  55.     taskList += tasks[i].getTaskStatus() + "\\\"title\\\":\\\"" + tasks[i].getName() + "\\\"}";
  56.     строки отличаются только на запятую
  57.     код - не DRY
  58.  
  59.     есть много вариантов хороших - как сделать так, чтобы не дублировать повторяющуюся часть
  60.     самый примитивный - сначала вне if добавлять одинаковую часть
  61.     затем - анализируя - добавлять запятую
  62.  
  63.     можно чуть умнее - в цикле добавлять запятую всегда
  64.     после цикла проанализировать - есть ли лишняя запятая - и у этом случае ее удалить
  65.  
  66.     может быть еще красивее - за счет использования String.join(",", ...)
  67.       Настаивать на этих изменениях не буду, советую попробовать)
  68.         https://docs.oracle.com/javase/8/docs/api/java/lang/String.html
  69.         http://joxi.ru/V2VBQLqf0ZW692 - фактически, вызываем второй из этих методов
  70.         (переменную типа List<String> тут можно передать в качестве второго параметра)
  71.  
  72.         https://habrahabr.ru/post/260767/
  73.         http://javarevisited.blogspot.com/2016/06/10-examples-of-joining-string-in-java-8.html
  74.  
  75.     Не настаиваю я только на использовании третьего самого красивого варианта
  76.     Но сделать код DRY - нужно обязательно
  77.  
  78.     Когда речь идет о коде с не самой примитивной логикой (есть if-ы, циклы и пр)
  79.     то критически важно - чтобы код был DRY
  80.     иначе - эти все повторения будут источником бесконечных ошибок
  81.     пример - что-то поменялось, в одной части if-а поправили, а в повторяющемся коде другой части if-а - не поправили
  82. */
  83. ******************************************
  84.     private void given (String taskStatus, String... taskTexts){
  85.     private void given (Task... tasks){
  86.     private void givenAllActive (String... taskTexts){
  87.     private void givenAllCompleted (String... taskTexts){
  88.  
  89.     /*
  90.         Во всех этих методах - код очень похож
  91.         Самый универсальный из этих методов - given (Task... tasks)
  92.         т к он позволяет создать любой набор тасок
  93.  
  94.         остальные - это тот же алгоритм, чуть упрощенный, но и только
  95.         это тот же алгоритм
  96.         недостаток этих повторений - такой же, как я выше описывала
  97.         если будут проблемы с гивенами - править придется четыре метода
  98.         и не факт, что все методы будут выправлены привильно
  99.  
  100.         поэтому - во избежание таких вот проблем -
  101.         делаем код DRY
  102.         в given (Task... tasks) - реализуем алгоритм (мы и внутри него уже код улучшили)
  103.  
  104.         а в остальных гивен-методах - будем переиспользовать - т е вызывать given (Task... tasks)
  105.         давай разберемся - какой набор гивенов нам нужен
  106.  
  107.         given (String taskStatus, String... taskTexts) - хорошая идея
  108.         для многих фиче-тестов будет достаточно создать однотипные таски
  109.  
  110.         теперь сравни вызовы
  111.         given (ACTIVE, "a", "b")
  112.         givengivenAllActive ("a", "b")
  113.  
  114.         первый вариант даже выигрывает) - он лаконичнее
  115.         и обеспечивает оба варианта - и создать все активные таски, и все закомпличеные
  116.  
  117.         т е - избавляемся от givenAllActive и givenAllCompleted
  118.  
  119.         Идем дальше)
  120.         Мы реализуем full coverage
  121.         и нам будут требоваться в предварительных действиях - не только созданные таски
  122.         но и переход на нужный фильтр
  123.         и поскольку нам важно - чтобы сами фиче-тесты были лаконичными
  124.  
  125.         можно дореализовать
  126.         методы - чтобы переход на нужный фильтр выполнялся в гивен-методе
  127.         также уточню - что Java позволяет реализовать несколько методов с одинаковым именем - если набор параметров отличается
  128.         и уточню - что во всех дополнительных гивен-методах - мы будем вызывать given (Task... tasks) (самый универсальный, в котором реализован алгоритм)
  129.  
  130.         для  all фильтра - уже есть
  131.         given (String taskStatus, String... taskTexts)
  132.         given (String taskStatus, String... taskTexts)
  133.  
  134.         Сделаем такого же плана методы - для других фильтров
  135.         givenAtActive (Task... tasks)
  136.         givenAtCompleted (Task... tasks)
  137.  
  138.         givenAtActive (String taskStatus, String... taskTexts)
  139.         givenAtCompleted (String taskStatus, String... taskTexts)
  140.  
  141.         На самом деле - может будет в некоторых методах выходнее вызывать не given (Task... tasks), а какой-то другой из этих гивенов
  142.         Суть - только в given (Task... tasks) у нас алгоритм реализован
  143.         Остальные - лишь его используют
  144.  
  145.           чтобы использовать given (Task... tasks)
  146.              команды джаваскрипт
  147.              а мочь вместо этого переиспользовать уже созданные методы
  148.  
  149.              тебе нужно уметь преобразовывать
  150.              (TaskType, String... taskTexts)
  151.              в
  152.              (Task... tasks)
  153.  
  154.              в методы с параметрами (Task... tasks) можно передавать значения-массивы (Task[] tasks)
  155.  
  156.              вот и напиши метод
  157.              возвращающий Task[]
  158.              по данным (TaskType, String... taskTexts) - это будут его параметры
  159.  
  160.              таким образом
  161.              внутри
  162.              givenAt...(TaskType, String... taskTexts)
  163.  
  164.              ты сможешь вызывать
  165.              givenAtAll...(xxx(TaskType, String... taskTexts))
  166.     */
  167. ********************************************
  168.     public static final String ACTIVE = "{\\\"completed\\\":false, ";
  169.     public static final String COMPLETED = "{\\\"completed\\\":true, ";
  170.     ...
  171.         private Task aTask (String taskName, String taskStatus){
  172.             return new Task(taskName,taskStatus);
  173.         }
  174. /*
  175.     я могу вызвать метод, передав в качестве второго параметра любую строку
  176.     хоть вот так aTask ("task1", "green")
  177.     эта ошибка проявится уже только в момент запуска тестов, а на этапе компиляции - мы не получим никаких сообщений -
  178.     что что-то не так с вызовом метода
  179.  
  180.     вот для таких случаев очень хорошо подойдет использование enum
  181.     если параметр taskStatus у нас будет типа enum TaskStatus, то я только значение этого enum и смогу передать в качестве параметра
  182.     по-другому - будут выданы сообщения об ошибке
  183.  
  184.     переделай работу с этип параметром - используй для него тип enum
  185.  
  186.     Кстати, для любого значения из enum -  можно получать соотвествующую ему строку
  187.  
  188.     у нас задача - для каждого значения enum вернуть свою строку
  189.     enum - это тоже класс
  190.     у которого может быть и конструктор, и поля
  191.     например
  192. */
  193.  
  194. public enum Day {
  195.         MONDAY("понедельник"),
  196.         TUESDAY("вторник"),
  197.         WEDNESDAY("среда"),
  198.         THURSDAY("четверг"),//<<----------------------для каждого значения enum - вызов конструктора, фактически значение = объект класса
  199.         FRIDAY("пятница"),
  200.         SATURDAY("суббота"),
  201.         SUNDAY("воскресенье");
  202.  
  203.         String description;//<<---------------------------поле для хранения описания дня недели
  204.  
  205.         public Day(String description) {
  206.                 this.description = description;//<<---------------------------логика конструктора - запомнить для объекта его описание
  207.         }
  208.  
  209.         @Override
  210.         public String toString() {
  211.             return description;//<<---------------------------логика - вывести для объекта - то что для него заполнили
  212.         }
  213. }
  214.  
  215.  
  216. /*
  217.     все классы - потомки класса Object (enum - это тоже класс)
  218.     у Object есть метод toString()
  219.     который выполняет преобразование объекта к строке
  220.     реализовав такой метод в рамках класса SomeClass -
  221.     используя выражения типа "day is "+ Day.MONDAY
  222.     получишь строку "day is понедельник"
  223.  
  224.     toString() - можно грамотно использовать в рамках всех вспомогательных классов и enum-ов
  225.     это позволит упростить код
  226.  
  227.     конструкторы в enum-ах как раз и могут помочь решению задачи
  228.     для каждого значения enum вернуть свою строку
  229.  
  230.     попробуй применить эти подходы
  231.  
  232. сам почитай про enum тоже, вот хороший пример
  233. http://javarevisited.blogspot.com/2011/08/enum-in-java-example-tutorial.html
  234. */
  235. ****************************************************************************
  236.  
  237. /*
  238.     Если смог применить toString() - для enum
  239.     подумай и про класс Task
  240.  
  241.     как думаешь - если в нем реализовать удобный тебе toString() - какой код можно реализовать красивее?
  242. */
  243. ******************************************************************
  244.  
  245. /*
  246. AtTodoMVCPageWithClearedDataAfterEachTest
  247.  
  248. /*
  249.     еще наворот
  250.  
  251.     мы наследуем тест-класс от AtTodoMVCPageWithClearedDataAfterEachTest
  252.  
  253.     перед запуском теста - открываем наше приложение
  254.     после - чистим локалсторидж
  255.  
  256.     гивены можно вызывать и для варианта, когда надо задать пустой список тасок
  257.     значит - можно вызывать в каждом тест-методе гивен-метод
  258.     и убоать очистку локал сториджа после теста - вот уже облегчили код
  259.  
  260.     дальше - раз все тесты происхолят на после открытого одного и того же урла
  261.     можно вначале гивен-метода проверить
  262.     если сейчас урл не такой, то открыть нужный урл
  263.     этот кусочек кода можно оформить в виде метода,
  264.     который будет вызываться вначле гивен-метода
  265.     такого плана методы = если сейчас не так, то сделать так
  266.     часто называют, начиная со слова ensure = обеспечить
  267.  
  268.     вот и не нужен нам код - по открытию урла в бифор-методе
  269.     сразу вопрос - какой предок нужен тест-классу)
  270.  
  271.     вот тебе и еще одна оптимизация)
  272.     кода меньше
  273.     сущностей меньше
  274.     действий лишних меньше
  275. */
  276. **************************************
  277.  
  278. /*
  279.     пока не анализирую покрытие - и так работы много, это уже в следующий раз
  280.     отмечу только важные моменты
  281. */
  282.  @Test
  283.     public void testEditAtAll(){
  284.         given(ACTIVE, "1");
  285.  
  286.         edit("1","edited 1");
  287.         assertTasksAre("edited 1");
  288.         assertItemsLeft(1);
  289.     }
  290.  
  291.  
  292.   @Test
  293.     public void testEditAtActive(){
  294.         given(aTask("1", ACTIVE));
  295.         filterActive();
  296.  
  297.         edit("1", "edited 1");
  298.         assertTasksAre("edited 1");
  299.         assertItemsLeft(1);
  300.     }
  301. /*
  302.     вот - 2 теста одной фичи (на разных контекстах)
  303.     было бы лучше - если бы в таких тестах - тестах одной фичи - использовались разные тестовые ситуации
  304.     гивены у нас быстрые и надежные
  305.     вот и воспользуемся этим
  306.  
  307.     например
  308.     редактируем единственную таску
  309.     редактируем вторую таску
  310.     редактируем вторую таску при том, что есть третья - не видимая на этом фильтре
  311.  
  312.     такой подход даст лучшее покрытие - мы больше тестовых витуаций проверим
  313.  
  314.     касается всех фиче-тестов
  315. */
  316. ****************************************
  317.  
  318.     @Test
  319.     public void testSwitchFromActiveToAll(){
  320.         given(aTask("1", ACTIVE));
  321.         filterActive();
  322.  
  323.         filterAll();
  324.         assertTasksAre("1");
  325.         assertItemsLeft(1);
  326.     }
  327.  
  328. /*
  329.     было = видна таска 1
  330.     перешли на фильтр
  331.     стало = видна таска 1
  332.  
  333.     что она видна - это праильно
  334.     да только  - работает ли переход на фильтр
  335.     ведь такого эффекта ты добъешься и при нерабочем переходе на фильтр
  336.  
  337.     чтобы проверить точно - реализуй
  338.     было видна таска 1 (а есть еще и не видимая 2)
  339.     перешли на фильтр
  340.     стало - видны обе таски
  341.  
  342.     было-стало - разные
  343.     и стало = правильное
  344.  
  345.     соотвественно - проверили точно
  346.  
  347.     один из тестов для фильтеринга реализуй с 3-мя тасками - чтоб проверить -
  348.     что фильтраниця не на одну таску распространяется
  349.  
  350. */
  351. ********************************************
  352.  
  353. http://joxi.ru/zANDEYxul9L4ym
  354.  
  355. /*
  356.     Судя по тест-плану - ты реализовал full coverage без оптимизаций
  357.  
  358.     оптимизировать - не обязательно
  359.     на картинке - показала - что можно было бы не покрывать в случае оптимизации
  360.  
  361. в чем оптимизация
  362.     - что покрыто в е2е - не покрываем фиче-тестами
  363.     - низкоприоритетное  - покрываем единожды, на каком-то из контекстов (пример - delete by emptying text)
  364.     - низкоприоритетные варианты фичи, у которой есть покрытые варианты - не покрываем (пример - reopen all & add)
  365.  
  366. */
Advertisement
Add Comment
Please, Sign In to add comment