Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- *******************************************
- /*
- Для первой версии этого задания - очень прилично)
- сначала разберемся с гивенами)
- */
- *******************************************
- public class Task
- /*
- Этот класс можно было в рамках этого задания - объявить внутри тест-класса
- Т к только там он используется, и т к в этом задании мы еще не ставили себе цели -
- отделить вспомогательные методы от тест-класса
- Эту задачу - будем решать в следующих работах
- Пока объяви класс Task внутри самого тест-класса
- Иначе - уже сейчас придется обсуждать - как лучше вынести вспомогательное из тест-класса
- Давай этот момент отложим - и так много чего в этом задании надо сделать
- */
- ********************************************
- @Step
- private void given (Task... tasks){
- String setItem = "localStorage.setItem(\"todos-troopjs\", ";
- String startOfTaskArray = "\"[";
- String endOfTaskArray = "]\")" ;
- String taskList = "";
- for (int i = 0; i < tasks.length; i ++){
- if (i != tasks.length - 1){
- taskList += tasks[i].getTaskStatus() + "\\\"title\\\":\\\"" + tasks[i].getName() + "\\\"}, ";
- }
- else {
- taskList += tasks[i].getTaskStatus() + "\\\"title\\\":\\\"" + tasks[i].getName() + "\\\"}";
- }
- }
- executeJavaScript(setItem + startOfTaskArray + taskList + endOfTaskArray);
- refresh();
- }
- /*
- сравни строки
- executeJavaScript(setItem + startOfTaskArray + taskList + endOfTaskArray);
- и
- executeJavaScript("localStorage.setItem(\"todos-troopjs\", " + "\"[" + taskList + "]\")");
- получилось - не намного длиннее, не менее DRY, и намного проще
- избавься от этих трех переменных, они только необоснованно усложняют код
- дальше сравниваем
- taskList += tasks[i].getTaskStatus() + "\\\"title\\\":\\\"" + tasks[i].getName() + "\\\"}, ";
- и
- taskList += tasks[i].getTaskStatus() + "\\\"title\\\":\\\"" + tasks[i].getName() + "\\\"}";
- строки отличаются только на запятую
- код - не DRY
- есть много вариантов хороших - как сделать так, чтобы не дублировать повторяющуюся часть
- самый примитивный - сначала вне if добавлять одинаковую часть
- затем - анализируя - добавлять запятую
- можно чуть умнее - в цикле добавлять запятую всегда
- после цикла проанализировать - есть ли лишняя запятая - и у этом случае ее удалить
- может быть еще красивее - за счет использования String.join(",", ...)
- Настаивать на этих изменениях не буду, советую попробовать)
- https://docs.oracle.com/javase/8/docs/api/java/lang/String.html
- http://joxi.ru/V2VBQLqf0ZW692 - фактически, вызываем второй из этих методов
- (переменную типа List<String> тут можно передать в качестве второго параметра)
- https://habrahabr.ru/post/260767/
- http://javarevisited.blogspot.com/2016/06/10-examples-of-joining-string-in-java-8.html
- Не настаиваю я только на использовании третьего самого красивого варианта
- Но сделать код DRY - нужно обязательно
- Когда речь идет о коде с не самой примитивной логикой (есть if-ы, циклы и пр)
- то критически важно - чтобы код был DRY
- иначе - эти все повторения будут источником бесконечных ошибок
- пример - что-то поменялось, в одной части if-а поправили, а в повторяющемся коде другой части if-а - не поправили
- */
- ******************************************
- private void given (String taskStatus, String... taskTexts){
- private void given (Task... tasks){
- private void givenAllActive (String... taskTexts){
- private void givenAllCompleted (String... taskTexts){
- /*
- Во всех этих методах - код очень похож
- Самый универсальный из этих методов - given (Task... tasks)
- т к он позволяет создать любой набор тасок
- остальные - это тот же алгоритм, чуть упрощенный, но и только
- это тот же алгоритм
- недостаток этих повторений - такой же, как я выше описывала
- если будут проблемы с гивенами - править придется четыре метода
- и не факт, что все методы будут выправлены привильно
- поэтому - во избежание таких вот проблем -
- делаем код DRY
- в given (Task... tasks) - реализуем алгоритм (мы и внутри него уже код улучшили)
- а в остальных гивен-методах - будем переиспользовать - т е вызывать given (Task... tasks)
- давай разберемся - какой набор гивенов нам нужен
- given (String taskStatus, String... taskTexts) - хорошая идея
- для многих фиче-тестов будет достаточно создать однотипные таски
- теперь сравни вызовы
- given (ACTIVE, "a", "b")
- givengivenAllActive ("a", "b")
- первый вариант даже выигрывает) - он лаконичнее
- и обеспечивает оба варианта - и создать все активные таски, и все закомпличеные
- т е - избавляемся от givenAllActive и givenAllCompleted
- Идем дальше)
- Мы реализуем full coverage
- и нам будут требоваться в предварительных действиях - не только созданные таски
- но и переход на нужный фильтр
- и поскольку нам важно - чтобы сами фиче-тесты были лаконичными
- можно дореализовать
- методы - чтобы переход на нужный фильтр выполнялся в гивен-методе
- также уточню - что Java позволяет реализовать несколько методов с одинаковым именем - если набор параметров отличается
- и уточню - что во всех дополнительных гивен-методах - мы будем вызывать given (Task... tasks) (самый универсальный, в котором реализован алгоритм)
- для all фильтра - уже есть
- given (String taskStatus, String... taskTexts)
- given (String taskStatus, String... taskTexts)
- Сделаем такого же плана методы - для других фильтров
- givenAtActive (Task... tasks)
- givenAtCompleted (Task... tasks)
- givenAtActive (String taskStatus, String... taskTexts)
- givenAtCompleted (String taskStatus, String... taskTexts)
- На самом деле - может будет в некоторых методах выходнее вызывать не given (Task... tasks), а какой-то другой из этих гивенов
- Суть - только в given (Task... tasks) у нас алгоритм реализован
- Остальные - лишь его используют
- чтобы использовать given (Task... tasks)
- команды джаваскрипт
- а мочь вместо этого переиспользовать уже созданные методы
- тебе нужно уметь преобразовывать
- (TaskType, String... taskTexts)
- в
- (Task... tasks)
- в методы с параметрами (Task... tasks) можно передавать значения-массивы (Task[] tasks)
- вот и напиши метод
- возвращающий Task[]
- по данным (TaskType, String... taskTexts) - это будут его параметры
- таким образом
- внутри
- givenAt...(TaskType, String... taskTexts)
- ты сможешь вызывать
- givenAtAll...(xxx(TaskType, String... taskTexts))
- */
- ********************************************
- public static final String ACTIVE = "{\\\"completed\\\":false, ";
- public static final String COMPLETED = "{\\\"completed\\\":true, ";
- ...
- private Task aTask (String taskName, String taskStatus){
- return new Task(taskName,taskStatus);
- }
- /*
- я могу вызвать метод, передав в качестве второго параметра любую строку
- хоть вот так aTask ("task1", "green")
- эта ошибка проявится уже только в момент запуска тестов, а на этапе компиляции - мы не получим никаких сообщений -
- что что-то не так с вызовом метода
- вот для таких случаев очень хорошо подойдет использование enum
- если параметр taskStatus у нас будет типа enum TaskStatus, то я только значение этого enum и смогу передать в качестве параметра
- по-другому - будут выданы сообщения об ошибке
- переделай работу с этип параметром - используй для него тип enum
- Кстати, для любого значения из enum - можно получать соотвествующую ему строку
- у нас задача - для каждого значения enum вернуть свою строку
- enum - это тоже класс
- у которого может быть и конструктор, и поля
- например
- */
- public enum Day {
- MONDAY("понедельник"),
- TUESDAY("вторник"),
- WEDNESDAY("среда"),
- THURSDAY("четверг"),//<<----------------------для каждого значения enum - вызов конструктора, фактически значение = объект класса
- FRIDAY("пятница"),
- SATURDAY("суббота"),
- SUNDAY("воскресенье");
- String description;//<<---------------------------поле для хранения описания дня недели
- public Day(String description) {
- this.description = description;//<<---------------------------логика конструктора - запомнить для объекта его описание
- }
- @Override
- public String toString() {
- return description;//<<---------------------------логика - вывести для объекта - то что для него заполнили
- }
- }
- /*
- все классы - потомки класса Object (enum - это тоже класс)
- у Object есть метод toString()
- который выполняет преобразование объекта к строке
- реализовав такой метод в рамках класса SomeClass -
- используя выражения типа "day is "+ Day.MONDAY
- получишь строку "day is понедельник"
- toString() - можно грамотно использовать в рамках всех вспомогательных классов и enum-ов
- это позволит упростить код
- конструкторы в enum-ах как раз и могут помочь решению задачи
- для каждого значения enum вернуть свою строку
- попробуй применить эти подходы
- сам почитай про enum тоже, вот хороший пример
- http://javarevisited.blogspot.com/2011/08/enum-in-java-example-tutorial.html
- */
- ****************************************************************************
- /*
- Если смог применить toString() - для enum
- подумай и про класс Task
- как думаешь - если в нем реализовать удобный тебе toString() - какой код можно реализовать красивее?
- */
- ******************************************************************
- /*
- AtTodoMVCPageWithClearedDataAfterEachTest
- /*
- еще наворот
- мы наследуем тест-класс от AtTodoMVCPageWithClearedDataAfterEachTest
- перед запуском теста - открываем наше приложение
- после - чистим локалсторидж
- гивены можно вызывать и для варианта, когда надо задать пустой список тасок
- значит - можно вызывать в каждом тест-методе гивен-метод
- и убоать очистку локал сториджа после теста - вот уже облегчили код
- дальше - раз все тесты происхолят на после открытого одного и того же урла
- можно вначале гивен-метода проверить
- если сейчас урл не такой, то открыть нужный урл
- этот кусочек кода можно оформить в виде метода,
- который будет вызываться вначле гивен-метода
- такого плана методы = если сейчас не так, то сделать так
- часто называют, начиная со слова ensure = обеспечить
- вот и не нужен нам код - по открытию урла в бифор-методе
- сразу вопрос - какой предок нужен тест-классу)
- вот тебе и еще одна оптимизация)
- кода меньше
- сущностей меньше
- действий лишних меньше
- */
- **************************************
- /*
- пока не анализирую покрытие - и так работы много, это уже в следующий раз
- отмечу только важные моменты
- */
- @Test
- public void testEditAtAll(){
- given(ACTIVE, "1");
- edit("1","edited 1");
- assertTasksAre("edited 1");
- assertItemsLeft(1);
- }
- @Test
- public void testEditAtActive(){
- given(aTask("1", ACTIVE));
- filterActive();
- edit("1", "edited 1");
- assertTasksAre("edited 1");
- assertItemsLeft(1);
- }
- /*
- вот - 2 теста одной фичи (на разных контекстах)
- было бы лучше - если бы в таких тестах - тестах одной фичи - использовались разные тестовые ситуации
- гивены у нас быстрые и надежные
- вот и воспользуемся этим
- например
- редактируем единственную таску
- редактируем вторую таску
- редактируем вторую таску при том, что есть третья - не видимая на этом фильтре
- такой подход даст лучшее покрытие - мы больше тестовых витуаций проверим
- касается всех фиче-тестов
- */
- ****************************************
- @Test
- public void testSwitchFromActiveToAll(){
- given(aTask("1", ACTIVE));
- filterActive();
- filterAll();
- assertTasksAre("1");
- assertItemsLeft(1);
- }
- /*
- было = видна таска 1
- перешли на фильтр
- стало = видна таска 1
- что она видна - это праильно
- да только - работает ли переход на фильтр
- ведь такого эффекта ты добъешься и при нерабочем переходе на фильтр
- чтобы проверить точно - реализуй
- было видна таска 1 (а есть еще и не видимая 2)
- перешли на фильтр
- стало - видны обе таски
- было-стало - разные
- и стало = правильное
- соотвественно - проверили точно
- один из тестов для фильтеринга реализуй с 3-мя тасками - чтоб проверить -
- что фильтраниця не на одну таску распространяется
- */
- ********************************************
- http://joxi.ru/zANDEYxul9L4ym
- /*
- Судя по тест-плану - ты реализовал full coverage без оптимизаций
- оптимизировать - не обязательно
- на картинке - показала - что можно было бы не покрывать в случае оптимизации
- в чем оптимизация
- - что покрыто в е2е - не покрываем фиче-тестами
- - низкоприоритетное - покрываем единожды, на каком-то из контекстов (пример - delete by emptying text)
- - низкоприоритетные варианты фичи, у которой есть покрытые варианты - не покрываем (пример - reopen all & add)
- */
Advertisement
Add Comment
Please, Sign In to add comment