julia_v_iluhina

Untitled

Nov 10th, 2016
83
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 15.80 KB | None | 0 0
  1. import copy
  2.  
  3. tasks_for_reset = copy.deepcopy(tasks)
  4.  
  5. /*
  6.     предлагаю import copy
  7.     выполнить вначале кода
  8.     там где и остальные импорты
  9.     хотя - технически и так ок
  10.  
  11.     будет упорядоченнее
  12. */
  13. ********************
  14. def reset_tasks():
  15.     ...
  16.     return make_response(jsonify({'reset is completed': 'successfully'}), 205)
  17. /*
  18.     можно вернуть get_tasks()
  19.     получим результат - как и у собственно get_tasks()
  20.  
  21.     оба гет-запроса будут работать аналогично, насколько это возможно
  22. */
  23. ************************
  24.  http://joxi.ru/Y2LXgYnfnKLq02
  25. /*
  26.     вот еще источник проблем)
  27.  
  28.     если мы создаем первую таску (например, перед этим - все таски удалили)
  29.     то получим проблему)
  30.     не будет у нас предыдущего элемента)
  31.  
  32.     все же - если элементов в коллекции тасок нету - то у первой таски должен быть ид=1
  33.  
  34.     https://lancelote.gitbooks.io/intermediate-python/content/book/ternary_operators.html
  35.     https://lancelote.gitbooks.io/intermediate-python/content/book/comprehensions.html (dict абстракции)
  36.     http://www.diveintopython.net/native_data_types/index.html#odbchelper.dict
  37.  
  38. */
  39. ****************************
  40. public class Helpers {
  41. /*
  42.     это - по сути, аналог пейджа-модуля
  43.  
  44.     Теперь у нас будет пекедж не pages, a resources.  А правила работы с таким классом - аналогичные.
  45.  
  46.     Поскольку мы работаем только с тасками - в имена методов-действий можно не включать слово Tasks
  47.     Имена методов-проверок - по-прежнему указываем точно
  48.  
  49.     Логично было бы назвать класс Tasks (будем реализовывать как ресурс-модуль, а не ресурс-объект)
  50.     И в коде потом можно без статического импорта писать
  51.             Response response = Tasks.create(URI, "give lesson");
  52.  
  53.     Это было бы и наглядно, и на будущее - на случай, если в тесте появятся запросы к другим ресурсам
  54.  
  55.     Tasks - неплохое имя
  56.     но у нас есть класс Task
  57.     и можно сказать - что мы используем один термин для достаточно разных понятий….
  58.  
  59.     Можно в таком случае для класса-ресурса использовать TasksApi или  TasksRest в таком случае…
  60.  
  61.     Но и Tasks - тоже неплохо…, но хуже)
  62.     Можно пойти на эту уступку в принципе - код понятный, названия наглядные
  63.  
  64.     Уже по пути
  65.     На реальном проекте обычно создают класс-ресурс (объект или модуль) не сразу, когда начали писать тесты.
  66.     А позже - когда появится необходимость переиспользовать вспомогательные методы в разных тест-классах.
  67.     Или если одни более квалифицированные члены команды разрабатывают класс-ресурс,
  68.     а другие - используют для разработки тестов. Но или если так принято в данной команде)
  69.     Т е - это делается обычно при необходимости. С пейджами - в общем аналогично.
  70. */
  71. ************************************
  72. public static final String URI = "http://localhost:5000/todo/api/v1.0/tasks";
  73. /*
  74.     было бы совсем ок, если бы в Сonfiguration.baseUrl, в котором именно домен был сохранен
  75.     что бы его можно было от случая к случаю реконфигурить...
  76.     Ведь это как раз та часть урла - которая не принадлежит ресурсу - "http://localhost:5000/"
  77.     и зависит от того на каком сервере/по-какому-адресу ресурс/веб-сервис задеплоен
  78.  
  79.     На самом деле, здесь есть несколько способов как лучше сделать
  80.  
  81.     Первый, если есть уверенность, что тебе не нужно будет одновременно/параллельно посылать запросы на разные урлы
  82.     То тогда можно использовать Configuration.baseUrl - типа обычная глобальная переменная
  83.  
  84.     если нет, тогда лучше "ооп" подход, когда обьект-ресурс помнит свой базовый урл (доменную часть)
  85.     который передается при создании через конструктор
  86. */
  87. **********************************
  88. public static Invocation.Builder requestTo(String uri) {
  89. public static Invocation.Builder authorized(Invocation.Builder requestBuilder) {
  90. /*
  91.     По сути - это универсальные методы
  92.     их лучше вынести из класса-ресурса
  93.     в отдельный класс с универсальными методами
  94.  
  95.     а чтоб они точно были универсальными - передавай "miguel:python" как параметр в метод authorized
  96.     что это - это credentials
  97.  
  98.     а класс уместно назвать например RestHelpers
  99. */
  100. ***************************
  101. private static Response response;
  102. ...
  103. public static int getResponseStatus() {
  104.    return response.getStatus();
  105. }
  106. ...
  107. public static String getErrorAnswer() {
  108.    return response.readEntity(ErrorContainer.class).getError();
  109. }
  110. ...
  111. /*
  112.     ну, немного магии таки есть в таком решении - когда в переменной ресурса - сохраняется ответ
  113.     и потом мы с ним работаем)
  114.  
  115.     не магическое решение - это чтобы сами методы - возвразщали response
  116.     и в тест-методах - мы получили его в там объявленную переменную
  117.     и его проверили
  118.  
  119.     я предлагаю тоже магическое решение
  120.     но - оно здорово упростит нам жизнь
  121.     потому и предлагаю
  122. */
  123.     @Test
  124.     public void testReadTasks() {
  125.  
  126.         getAuthorizedAccess();
  127.  
  128.         assertEquals(200, getResponseStatus());
  129.         assertEquals(2, getTasksSize());
  130.         assertEquals("Buy groceries", getTask(0).getTitle());
  131.     }
  132.  
  133.  
  134. //вот - не магический вариант
  135.  
  136.     @Test
  137.     public void testReadTasks() {
  138.         Response response = Tasks.get();
  139. //его можно упростить до вот такого
  140.     @Test
  141.     public void testReadTasks() {
  142.         List<Task> receivedTasks = Tasks.get();
  143. /*
  144.  
  145.     Правильный статус ответа на каждый из запросов - строго определенный
  146.     И если мы будем проверять статут ответа в тест-методе - то надо об этом думать и вспоминать - какой статус в каких случаях верный
  147.     И можно выкрутиться - проверять статус ответа в нутри степа, а возвращать собственно entity из запроса.
  148.     Сразу пара потенциально полезных моментов)
  149.  
  150.  
  151.     Если встроить проверку response кода прямо в сам степ
  152.     Тут сразу появляется интересный нюанс
  153.     Дело в том, что мы так спрячем тестовую логику внутрь степа, что не очень хорошо
  154.     С другой стороны - эта проверка = само собой разумеющееся
  155.     Эта проверка достаточно стандартная и всегда будет повторяться после вызова степа (если будет жить вне степа)
  156.     А раз так - то почему бы и не спрятать?
  157.     На самом деле - нет однозначного ответа на этот вопрос...
  158.     Так - со спрятанной проверкой - код станет проще во всех тестах - но втанет до некоторой степени “магическим”
  159.     Тут надо решать самостоятельно - как лучше )
  160.     На твое усмотрение
  161.     Еще момент
  162.     В этих API тестах - самих тестов может быть не так уж и много -
  163.     чтоб еще и заморачиваться над DRY кода...нужно и этот аспект учитывать
  164.  
  165.  
  166.     Но если пойти этим путем = прятать в степе проверку статуса response, то код будет намного более удобным:
  167.     У нас в тест-методах останется лишь проверка состояния тасок
  168.     Что код сделает легче
  169.     И немного магичнее )
  170. */
  171. ************************************
  172. public class RESTfulTasksTest {
  173.  
  174.     @Before
  175.     public void resetBase(){
  176.         authorized(requestTo(URI + "/reset")).get();
  177.     }
  178.     /*
  179.         я бы в классе-ресурсе - реализовала метод reset()
  180.  
  181.         смотри - этот гивен - это часть тест логики
  182.  
  183.         как минимум нельзя прятать такое в предке тест-класса
  184.         этот гивен на самом деле такой важный, что лучше вообще не скрывать его
  185.         ни в каком базовом классе....
  186.  
  187.         его желательно "видеть" в самом тесте
  188.  
  189.         часто даже не стоит такие вещи в @Before выносить, не смотря на то что код будет не DRY
  190.         но будет еще более явным и очевидным)
  191.  
  192.         Хотя в этом случае наверное с @Before будет таки лучше )
  193.  
  194.         а в классы с именем BaseTest - желательно выносить что-то такое что однозначно общее для всех тестов,
  195.         какие-то настройки может конфигурационные, которые в контексте тест логики смысла не имеют
  196.         и их не грех "скрыть с глаз долой"
  197.  
  198.     */
  199. *************************
  200. assertEquals("Buy groceries", getTask(0).getTitle());
  201. assertEquals("Learn Python", getTask(1).getTitle());
  202.  
  203. /*
  204. У наших тасок - есть не только заголовок, но и другие свойства
  205. И при сравнении - это все должно быть сверено
  206. Поскольку после ресета - мы получаем заведомо оинаковые таски -
  207. можно в тест-классе объявить и инициализировать массив тасок DEFAULT_TASKS и его использовать
  208.  
  209. С таким вынесением тестовых данных в переменные надо быть осторожным
  210. Важно - не надо тестовые данные объявлять в ресурс модуле (опять аналогия с пейджом - мы и там такого правила придерживались)
  211. Тут и правда есть смысл объявить эти данные
  212. Часто тестовые данные разумно оставлять в логике самих тестов - таким образом код тестов более очевидный. Пример - тудуэмвиси тесты
  213. */
  214. *********************************
  215.     @Test
  216.     public void testUpdate() {
  217.         int id = 2;
  218.         updateTask("updated description", true, "updated task", id);
  219.         assertEquals(200, getResponseStatus());
  220.  
  221.         Task receivedTask = getResponseTask();
  222.  
  223.         assertEquals("updated description", receivedTask.getDescription());
  224.         assertTrue(receivedTask.isDone());
  225.         assertEquals("updated task", receivedTask.getTitle());
  226.         assertEquals(Helpers.URI + "/" + id, receivedTask.getUri());
  227.     }
  228.  
  229. //или
  230.     @Test
  231.     public void testUpdate() {
  232.         Task task = new Task("t2 title", "t2 description", true, TasksApi.uri + "/2");
  233.  
  234.         TasksApi.update(task);
  235.  
  236.         TasksApi.assertTasks(DEFAULT_TASKS[0], task);
  237.     }
  238. /*
  239.     сразу несколько моментов
  240.  
  241.     посмотри на информацию по этим линкам
  242.     http://www.java2s.com/Tutorial/Java/0140__Collections/CheckingforEquality.htm
  243.     http://www.javapractices.com/topic/TopicAction.do?Id=17
  244.     http://javadevnotes.com/java-array-to-list-examples
  245.  
  246.     и мы сможем сравнивать - как таску с таской, так и список тасок со списком тасок - используя
  247.     assertEquals
  248.  
  249.     А если реализуешь метод toString для класса Task - и сообщение об ошибке будет более информативным.
  250.  
  251.     После выполненного действия однозначно нужно проверить список тасок
  252.     получить его и сверить с ожидаемыми значениями
  253.     именно такая проверка - проверит логику работы, а не только правильность ответа
  254.    
  255.     нужно или нет проверять и таску, которую возвращает запрос при редактировании - это уже от разного зависит
  256.     если это уже где-то контролируется - можно опустить
  257.     а если нет - то лучше покрыть
  258.     тоже - возможно - стоит скрыть такую проверку внутри TasksApi.update
  259.     спорно, на самом деле)
  260.     а может - внутри TasksApi.update - пусть проверяется только код ответа
  261.    
  262.     а в тест-методе - проверить возвращенную в ответе TasksApi.update таску
  263.     и следом - список тасок тоже проверить
  264.      
  265.     наверное - так будет погибче и попрозрачнее
  266.     надо будет - воспользуются результатом метода TasksApi.update и его проверят
  267.     а не надо - так и пренебрегут
  268.    
  269.     все же методы класса-ресурса (как и пейджа)
  270.     должны быть тоже достаточно гибкими
  271. */
Advertisement
Add Comment
Please, Sign In to add comment