julia_v_iluhina

Untitled

Jul 24th, 2016
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 37.25 KB | None | 0 0
  1. http://joxi.ru/a2X3dZMsyvwwKm
  2.  
  3. не забывай про .gitignore
  4. не держи лишнего в репозитории
  5. ************************************
  6. http://joxi.ru/Vm6QqxphxJ4xer
  7.  
  8. /*
  9.     пока не ясно - для чего изменил код - какие таски генерятся по умолчанию
  10.     пока не вижу пользы от этих изменений)
  11.    
  12.     мне кажется, данные поясняли - что есть title, что есть description
  13. */
  14. *******************************
  15.  
  16. http://joxi.ru/1A5zNxjuKlDnbr
  17.  
  18. /*
  19.     про реализацию reset - несколько моментов
  20.    
  21.     логика
  22.         ты тут фактически дублируешь код  из http://joxi.ru/Vm6QqxphxJ4xer
  23.         не DRY
  24.         Не надо в данном методе сервиса - дублировать коллекцию tasks
  25.         Нужно грамотно воспользоваться тем, что уже есть в коде
  26.         Если начальное состояние фиксировать в некой коллекции tasks_default,
  27.         а при старте и ресете - копировать в  tasks содержимое tasks_default
  28.         В python есть способ  - скопировать содержимое одного списка в другой с помощью одной операции,
  29.         а не переносить каждый элемент списка отдельно
  30.  
  31.         получишь более DRY код
  32.        
  33.         полезные линки
  34.         https://docs.python.org/2/library/copy.html
  35.         http://joxi.ru/Dr8vxzPFk3Kl32
  36.         http://stackoverflow.com/questions/2612802/how-to-clone-or-copy-a-list-in-python
  37.         http://joxi.ru/J2b9KdBt41qEpm
  38.        
  39.    теперь про то, какой метод HTTP ты для этого действия используешь
  40.    сейчас у тебя используется DELETE с URI= /todo/api/v1.0/tasks/reset
  41.    DELETE = удалить ресурс. И в URI по идее мы должны передать - что ж за ресурс мы удаляем
  42.    Кроме того, после этой операции тасок может и прибавится)
  43.    т к не факт, что на момент вызова метода было больше 2-ух тасок (а иначе - какой это delete)
  44.    смыслы слегка "уплыли"
  45.  
  46.  
  47.       какие наши варианты
  48.         “идеология REST” говорит - что можно использовать только специальные http methods
  49.         И только по определенному принципу
  50.         Например,
  51.         для создания - использовать post,
  52.         для апдейта - метод put
  53.         и т д
  54.        
  55.         И нам важно соблюсти этот принцип и свести написание сервисов к одному шаблону
  56.         Вся идея REST была в том, чтобы чтобы потом все могли “общаться на одном языке” и таким образом “понимать друг друга”
  57.        
  58.         можно было бы реализовать что-то типа такого
  59.         @app.route('/todo/api/v1.0/tasks/reset', methods = [‘PUT’]) (edited)
  60.        
  61.         НО, хотя мы и делаем “апдейт"
  62.         но - апдейт не ресурса...
  63.         т к reset - это не ресурс
  64.        
  65.         вот если бы мы для  /tasks посылали PUT, то было бы все честно
  66.         а /tasks/reset - это уже не ресурс
  67.         это просто “хак-урл” , чтобы нам выполнить определенное нужное нам действие
  68.         потому в данном случае абсолютно нормально - посылать GET
  69.         наверное, можно и PUT… решай самостоятельно
  70.        
  71.         уже лучше, чем DELETE, но все равно не очень...
  72.        
  73.         еще довод за GET
  74.         обрати внимание - все остальные запросы что-то возвращают - делают return …
  75.         это логично - клиент послал запрос, нужно ему что-то вернуть)
  76.         и тут было бы логично вернуть все таски = (то же, что возвращает запрос get)
  77.    
  78. */
  79.  
  80. *********************************
  81.  
  82. http://joxi.ru/krDOZldF07K01A
  83.  
  84. /*
  85.     ага...
  86.     ты так обошел ошибку - когда первую таску создаешь
  87.    
  88.     ну да...
  89.     полезно исправить)
  90.    
  91.     только можно красивее
  92.     фактически - у тебя в зависимости от условия - только заполнение id
  93.    
  94.     остальное - не зависит от условия
  95.     разумно это остальное - вынести из if-а
  96.    
  97.     будет DRY )
  98. */
  99. ***********************************
  100.  
  101. package ua.net.vmarchenko.credentials;
  102.  
  103.  
  104. public class TestData {
  105.  
  106.     public static final String URL = "http://localhost:5000/todo/api/v1.0/tasks";
  107.     public static final String RESET_URL = "http://localhost:5000/todo/api/v1.0/tasks/reset";
  108.     public static final String LOGIN = "miguel";
  109.     public static final String PASSWORD = "python";
  110.  
  111.     public static String usernameAndPassword = LOGIN + ":" + PASSWORD;
  112.     public static String authorizationHeaderValue = "Basic " + java.util.Base64.getEncoder().encodeToString(usernameAndPassword.getBytes());
  113. }
  114.  
  115. /*
  116.     давай отделим мух от котлет)
  117.    
  118.     пекедж называется credentials, класс TestData
  119.     а храним мы там URI, логин-пассворд и их производные....
  120.    
  121.     ну нет)
  122.    
  123.     URI - точно ни credentials, ни TestData
  124.     его разместим в другом месте)
  125.     ниже напишу
  126.     его - т к наш URI = "http://localhost:5000/todo/api/v1.0/tasks"
  127.     остальное - добавки к нему
  128.     тут тоже стоит быть DRY
  129.    
  130.     насчет логина-пароля и их производых
  131.     этот сервис подразумевает каких-то других юзеров, кроме miguel?
  132.     если бы да - то я согласилась бы с тобой, что стоило бы реализовать
  133.     класс UsersData в пекедже credentials
  134.     в котором есть информация о нескольких юзерах
  135.     и уж точно в таком классе не место логике преобразования логина-пароля в зашифрованую строку
  136.    
  137.     вывод - нам в полном составе такой класс не нужен
  138.    
  139.     гугли Single Responsibility principle
  140.    
  141.     многих вопросов бы тут у тебя не возникло - если бы сначала добил работы по селениуму
  142.     там бы скиллы прокачал по работе с классами
  143. */
  144. ************************************************
  145.  
  146. public class helpers {
  147.   /*
  148.     Имя класса - вспомни о конвеншенсах
  149.     правильнее разместить универсальные хелперы в ветке src\main
  150.     в пекедже core
  151.     и уточнить имя класса до RestHelpers
  152.   */
  153.  
  154.     public static Invocation.Builder requestTo(String url) {
  155.      /*
  156.         тут к реализации нет вопросов
  157.         все же корректнее назвать параметр uri
  158.         погугли при необходимости термин
  159.      */
  160.  
  161.     public static Invocation.Builder authorized(Invocation.Builder requestBuilder) {
  162.         return requestBuilder.header("Authorization", TestData.authorizationHeaderValue);
  163.         /*
  164.             а тут мы внутрь универсального метода впихнули прямую работу с тестовыми данными
  165.             так лучше не делать - ни для универсальных методов
  166.             ни для методов классов-пейджей или как будем делать сейчас - классов-ресурсов
  167.            
  168.             тестовые данные - отдельно
  169.             вспомогательные методы - отдельно
  170.            
  171.             надо что-то передать - делай методу параметр
  172.            
  173.             вот тут реализуй параметр String credentials
  174.             в который передашь "miguel:python"
  175.            
  176.             и тут, внутри метода - как раз и преобразуй "miguel:python" в зашифрованую строчку
  177.            
  178.             метод получится универсальным...
  179.         */
  180.     }
  181.  
  182.     public static void assertStatusCode(int statusCode) {
  183.         assertEquals(statusCode, ToDoAppRESTfulCRUDTests.response.getStatus());
  184.     }
  185.     /*
  186.         этот метод - явно не отсюда)
  187.         ему место в ToDoAppRESTfulCRUDTests - раз мы обращаемся к его данным
  188.        
  189.         еще подумаем - нужен ли тебе такой метод)
  190.        
  191.         уже точно - ему тут не место)
  192.        
  193.     */  
  194. }
  195. ******************************************  
  196.  
  197. http://joxi.ru/J2b1MVvs4N00pm
  198.  
  199. /*
  200.     это не ресурсы, а контейнеры
  201.     размести классы в пекедже containers
  202.    
  203.     набор классов - тоже вызывает вопросы
  204.     разберемся ниже)    
  205. */
  206. ******************************************
  207.  
  208. public class TasksContainer {
  209.  
  210.  
  211.     ...
  212.  
  213.     public static void assertTasks(List<Task> expectedTasks) {
  214.     public static List<Task> getAllTasks() {
  215.     public static boolean assertTitles(String ... expectedTitle) {
  216.     public static boolean assertDescriptions(String ... expectedDescription) {
  217.     public static boolean assertIsDone(Boolean ... isDone) {
  218. /*
  219.     а вот и отгадка)
  220.    
  221.     будем исправлять)
  222.    
  223.     Single Responsibility principle    
  224.     у каждого класса есть своя ответственность    
  225.     у этого - парсинг с JSON
  226.     и все)
  227.    
  228.     а вот эту функциональность - будем реализовывать в классе-ресурсе (аналог пейджа в Web UI тестировании)
  229.     может, не именно так, как єта функциональность тут реализована, но эту же самую))
  230. */
  231. **************************************************
  232.  
  233. public class Task {
  234.  
  235.  ...
  236.     public static Entity createTaskEntity(Task task){
  237. /*
  238.     Это тоже не логика для класса, участвующего в сериализации/десериализации
  239. */
  240.  
  241.     public static List<Task> getInitialTasksList() {
  242. /*
  243.     а вот это как раз тестовые данные)
  244.     тоже не место им тут)    
  245. */
  246.      
  247. /*
  248.     в каждом из этих классов - должны быть нужные поля + геттеры-сеттеры
  249.    
  250.     потом еще кое-что добавим
  251.    
  252.     но сейчас - только это
  253.    
  254.     остальное - ответственность других классов
  255. */      
  256. ************************************************
  257.  
  258. /*
  259.     да...
  260.     написала только - что нужно поубирать
  261.     а вот куда - пока не ясно...
  262.    
  263.     давай разбираться
  264. */
  265. ***************************************************
  266. /*
  267.     Вспомогательные методы разумно вынести в класс - аналог пейджа.
  268.     Теперь у нас будет пекедж не pages, a resources.
  269.     А правила работы с таким классом - аналогичные, как для класса-пейджа.
  270.     Размещай класс в ветке src\main - как то, что можно переиспользовать
  271.    
  272.     Поскольку мы работаем только с тасками - в имена методов-действий можно не включать слово Tasks
  273.     Имена методов-проверок - по-прежнему указываем точно
  274.    
  275.     Логично было бы назвать класс Tasks
  276.     (если будем реализовывать как ресурс-модуль, а не ресурс-объект -
  277.     в принципе - нет причин реализовывать как ресурс-объект, но тут
  278.     можешь и сам решить это - может у тебя будут свои резоны)
  279.    
  280.     И в коде потом можно без статического импорта писать
  281.             Response response = Tasks.create(URI, "give lesson");
  282.    
  283.    
  284.     Это было бы и наглядно, и на будущее - на случай, если в тесте появятся запросы к другим ресурсам
  285.    
  286.         Tasks - неплохое имя
  287.         но у нас есть класс Task
  288.         и можно сказать - что мы используем один термин для достаточно разных понятий….
  289.        
  290.         Можно в таком случае для класса-ресурса использовать TasksApi или  TasksRest в таком случае…
  291.        
  292.         Но и Tasks - тоже неплохо…, но хуже)
  293.         Можно пойти на эту уступку в принципе - код понятный, названия наглядные
  294.        
  295.        
  296.     Еще одно лирическое отступление)
  297.       На реальном проекте обычно создают класс-ресурс (объект или модуль) не сразу,
  298.       когда начали писать тесты.
  299.       А позже - когда появится необходимость переиспользовать
  300.       вспомогательные методы в разных тест-классах.
  301.       Или если одни более квалифицированные члены команды разрабатывают класс-ресурс,
  302.       а другие - используют для разработки тестов.
  303.       Ну или если так принято в данной команде)
  304.       Т е - это делается обычно при необходимости.
  305.       С пейджами - в общем аналогично.
  306.      
  307.       Мы сейчас реализуем проект сразус классом-ресурсом - чтобы разобраться, как это делать
  308. */
  309. ***************************************
  310.  
  311. /*
  312.     Что же там у нас будет
  313.    
  314.     наш URI "http://localhost:5000/todo/api/v1.0/tasks" - как раз URI для ресурса tasks
  315.     значит - тут и разместим
  316.     на самом деле - и с URI можно еще кое-что улучшить
  317.     но пока не будем распыляться - сделаем при следующих ревью
  318.    
  319.     практически для всех запросов к серверу нам нужно быть авторизированными
  320.     поскольку только в рамках этого класса мы реализуем методы, которые будут делать такие запросы
  321.     то тут и разместим метод, который будет делать авторизированный запрос для "miguel:python"
  322.     воспользуйся уже реализованным универсальным методом, передав туда в качестве параметра "miguel:python"
  323.     подумай, какой параметр должен быть у метода и что он должен возвращать
  324.    
  325.     а дальше - реализуем надор методов, работающих с ресурсом
  326.     поскольку работаем с тасками - уже в именах методов-действий это не уточняем
  327.     методы-действия
  328.       - получить таски
  329.       - создать таску (2 метода - только по заголовку или по всей информации)
  330.       - обновить таску
  331.       - удалить таску
  332.     метод-проверка
  333.       - проверить таски (нам нужен такой метод, который будет сверять ожидаемый результат с фактическим - для всех тасок)
  334.      
  335.   Есть интересный момент
  336.       Встраивать ли проверку статуса в метод-действие
  337.       Если встроить проверку response кода прямо в сам степ
  338.      
  339.       Дело в том, что если так делать - то мы спрячем тестовую логику внутрь степа, что не очень хорошо
  340.       С другой стороны - эта проверка = само собой разумеющееся
  341.       Эта проверка достаточно стандартная и всегда будет повторяться после вызова степа (если будет жить вне степа)
  342.       А раз так - то почему бы и не спрятать?
  343.       На самом деле - нет однозначного ответа на этот вопрос...
  344.       Так - со спрятанной проверкой - код станет проще во всех тестах - но код станет до некоторой степени “магическим”
  345.       Тут надо решать самостоятельно - как лучше )
  346.       На твое усмотрение
  347.      
  348.       Еще момент
  349.       В этих API тестах - самих тестов может быть не так уж и много -
  350.       чтоб еще и заморачиваться над DRY кода...нужно и этот аспект учитывать
  351.       Но если пойти этим путем = прятать в степе проверку статуса response, то код будет намного более удобным:)
  352.      
  353.       Этот момент также повлияет на то, что каждый из методов нам будет возвращать
  354.      
  355. */
  356. ***************************************
  357.  
  358.   public class ToDoAppRESTfulCRUDTests {
  359.   /*
  360.     конвеншенсы ) (имя тест-метода заканчивается на Test)
  361.     тексту CRUD - тоже не место в имени класса
  362.     т к его придется править - если будешь расширять функциональность
  363.    
  364.     ToDoAppRESTfulTest
  365.     RESTfulTest
  366.    
  367.     кстати, тут есть нюанс тоже - по кемел кейсу)
  368.     https://google.github.io/styleguide/javaguide.html#s5.3-camel-case
  369.     не RESTfulTest, а RestFulTest )
  370.    
  371.   */
  372.  
  373.   /*
  374.     тут - чтоб далеко не ходить - стоит как раз и объявить тестовые данные - 2 таски по умолчанию
  375.    
  376.       С таким вынесением тестовых данных в переменные надо быть осторожным
  377.       Важно - не надо тестовые данные объявлять в ресурс модуле
  378.       (опять аналогия с пейджом - мы и там такого правила придерживались)
  379.       Тут и правда есть смысл объявить эти данные
  380.       Часто тестовые данные разумно оставлять в логике самих тестов -
  381.       таким образом код тестов более очевидный. Пример - тудуэмвиси тесты
  382.       Но - если эти данные вынесены в переменные - то их уже и используй при проверках
  383.      
  384.   */
  385.  
  386.     public  static Response response;
  387.     /*
  388.         мудрено получилось)
  389.         сделать эту переменную статической, чтобы юзать ее в рамках другого класса...
  390.         не....
  391.         перебор)
  392.        
  393.         тебе не нужна в тест-классе такая переменная
  394.         все методы по реализации запросов к серверу - будут жить в классе-ресурсе
  395.         и в рамках каждого из методов просто создавай свой Response        
  396.     */
  397.     Client client;
  398.     /*
  399.         ну...
  400.         не вижу пока преимуществ в том, чтобы создавать перед тестом эту переменную и затем удалять
  401.        
  402.         в видео Яков ничего не говорил о том, что нужно закрывать (client.close();)
  403.        
  404.         пришлось таки мне поковыряться, чтоб сложить свое мнение - нужно ли
  405.         Пока на 100% в своем мнении не уверена - делись контраргументами, линками и т д)        
  406.        
  407.       Надо ли закрывать наш объект типа ClientBuilder
  408.           Это а самом деле интересный вопрос - надо ли закрывать наш объект типа ClientBuilder, который мы создали)
  409.           С одной стороны, надо - вот что написано в документации
  410.           https://docs.oracle.com/javaee/7/tutorial/jaxrs-client001.htm
  411.           и вот они примеры
  412.           http://www.programcreek.com/java-api-examples/index.php?class=javax.ws.rs.client.Client&method=close
  413.          
  414.           С другой стороны - вот что
  415.           http://grepcode.com/file/repo1.maven.org/maven2/javax.ws.rs/javax.ws.rs-api/2.0/javax/ws/rs/core/Response.java
  416.           а именно - вот это http://joxi.ru/8An6LoZhqdNzyA
  417.           вот тут еще почитай
  418.           http://stackoverflow.com/questions/35265534/closing-connection-in-get-request-using-jersey-client-2-22-1
  419.          
  420.           тут есть примеры тест-методов
  421.           http://www.hascode.com/2013/12/jax-rs-2-0-rest-client-features-by-example/
  422.          
  423.           плюс - эксперимент
  424.           создай объект  ClientBuilder до начала тестов(всех)
  425.           и пусть он используется для работы во всех тестах
  426.           а после всех тестов - закрой ранее созданный объект
  427.           тесты падают буквально при при попытке второго обращения к объекту ClientBuilder
  428.          
  429.           вывод - при нашем способе использования ClientBuilder - таки закрывать не нужно
  430.           достаточно реализовать так, как показано в видео -
  431.           для получения ответа на запрос используй  ClientBuilder.newClient().target(uri).request()
  432.          
  433.          
  434.       вывод - переменная тебе не нужна (наверное))) - если у тебя нету контраргументов )    
  435.  
  436.     */
  437.     WebTarget target;
  438.     /*
  439.         а эту ты и вовсе не используешь - создал и все
  440.     */
  441. ****************************************************  
  442.  
  443.  
  444.     @Before
  445.     public void setUp() {
  446.         client = ClientBuilder.newClient();
  447.         target = client.target(TestData.URL);
  448.     }
  449.  
  450.     @After
  451.     public void tearDown() {
  452.         requestTo(TestData.RESET_URL).delete();
  453.         client.close();
  454.     }
  455. /*
  456.     из вот этого кода - полезно делать ресет
  457.     и я бы советовала его делать не после теста, а до
  458.     т к не факт, что до начала работы у нас состояие = начальное
  459. */
  460. ***********************************************  
  461.  
  462.     @Test
  463.     public void testUnauthorizedTasksRead() {
  464.         response = requestTo(TestData.URL).get();
  465.         assertError("Unauthorized access");
  466.         assertStatusCode(403);
  467.     }
  468. /*
  469.     этот тест-метод - останется почти таким же
  470.    
  471.     за исключением того, что уйдут методы assertError и assertStatusCode
  472.     и тут - просто используй их реализацию
  473.    
  474.     на самом деле, вот такой код
  475.     assertEquals("Unauthorized access", response.readEntity(ErrorContainer.class).getError());
  476.     не сказать, чтобы сильно сложнее
  477.    
  478.     если и делать такой метод, то точно не в ErrorContainer (Single Responsibility)
  479.     и не в классе-ресурсе... - т к речь не о ресурсах
  480.     и не в RestHelpers - т к все же не универсальная вещь, а привязанная к конкретным структурам данных,
  481.     которые используются в нашем конкретном рест сервере
  482.     а если вспомнить - что пока только в этом месте нам нужно анализировать ошибку
  483.     так прекрасно можно обойтись строкой assertEquals("Unauthorized access", response.readEntity(ErrorContainer.class).getError());
  484.    
  485.     про проверку статуса
  486.     сравни
  487.     assertStatusCode(403);
  488.     и
  489.     assertEquals(403, response.getStatus());
  490.     вопрос - стоит оно того, чтоб его в метод заворачивать и куда-то прятать?
  491.  
  492. */  
  493. **********************************  
  494.  
  495.     @Test
  496.     public void testReadAll() {
  497.         /*
  498.             сомнительная польза от уточнения - что это ReadAll
  499.             а не Read
  500.            
  501.             если бы были оба варианта - тогда да, польза бы была)
  502.         */
  503.         response = authorized(requestTo(TestData.URL)).get();
  504.         /*
  505.             тут код может быть проще
  506.             List<Task> actualTasks = TasksApi.get();
  507.             это если внутри метода класса-ресурса проверять статус (см строка 335 в этом ревью)
  508.            
  509.             если не хочется прятать, то сложнее
  510.             Response response = TasksApi.get();
  511.             List<Task>  = response.readEntity(TaskContainer.class).getTask();
  512.            
  513.             я бы спрятала)          
  514.            
  515.         */
  516.         List<Task> expected = getInitialTasksList();
  517.         /*
  518.             это наши тестовые данные, и мы их расположили уже по-другому (выше есть про это)
  519.         */
  520.  
  521.         assertTasks(expected); // скрыта тестовая логика - нужно думать как реализовать
  522.         /*
  523.             а тут нам вполне подойдет assertEquals()
  524.             который сравнит ожидаемый и действительный результат
  525.            
  526.             для начала - оба эти результата - типа List<Task>
  527.            
  528.               посмотри на информацию по этим линкам
  529.               http://www.java2s.com/Tutorial/Java/0140__Collections/CheckingforEquality.htm
  530.               http://www.javapractices.com/topic/TopicAction.do?Id=17
  531.               http://javadevnotes.com/java-array-to-list-examples
  532.              
  533.               мы можем получить код проще
  534.               public static void assertTasks(Task... expectedTasks) {
  535.                       List<Task> actualTasks = get();
  536.                       assertEquals(Arrays.asList(expectedTasks), actualTasks);
  537.               }
  538.              
  539.               expectedTasks в данном случае - массив
  540.               А если реализуешь метод toString для класса Task - и сообщение об ошибке будет более информативным.
  541.  
  542.         */
  543. **************************************
  544. public class Task {
  545.  
  546.     String description;
  547.     boolean done;
  548.     private String title;
  549.     String uri;
  550.  
  551.     public Task() {
  552.  
  553.     }
  554.  
  555.     public Task(String title) {
  556.         this.title = title;
  557.     }
  558.  
  559. /*
  560.     перед обсуждением метода testCreateWithTitle - самое время поговорить о конструкторах
  561.    
  562.     нужен еще один конструктор, в котором ты можешь прописать все поля без исключения
  563.     нам нужен такой конструктор и для реализации второго testCreateWithFullInformation,
  564.     и для использования в сравнении ожидаемого и фактического результатов    
  565.    
  566.     и в случае, если в конструкторе ты что-то не прописываешь, задавай некое значение по умолчанию
  567.    
  568.     что-то типа такого
  569.      public Task(String title) {
  570.         this.title = title;
  571.         this.description = "";
  572.         this.done = false;
  573.         this.uri = "";
  574.     }
  575.    
  576.     цель - уйти от нуллов, они нам будут мешать при сравнениях тасок
  577.     если это не понятно пока - так реализуй сравнение и как раз увидишь проблемы)
  578.    
  579.     подумай, как код конструкторов можно сделать более DRY
  580.    
  581. */
  582.  
  583.  
  584.     @Test
  585.     public void testCreateTask() {
  586.     /*
  587.         определись с употреблением слова Task в именах методов
  588.         у тебя то так, то так
  589.     */
  590.         List<Task> expectedTasks = getInitialTasksList();
  591.         Task newTask = new Task("T 3");
  592.         expectedTasks.add(newTask);
  593.         /*
  594.             вот эти манипуляции с expectedTasks - лучше не делать....
  595.             чтобы не усложнять код
  596.         */
  597.         response = authorized(requestTo(TestData.URL)).post(createTaskEntity(newTask));
  598.  
  599.         assertTasks(expectedTasks);
  600.         /*
  601.             тут, и в остальных тест-методах можно применить такой способ работы
  602.             наша цель - получить максимально читаемый код
  603.            
  604.             TasksApi.create("t3 title"); - тут мы создали таску с таким-то тайтлом, проверили статус,
  605.             вернули созданную таску (при необходимости - можно что-то проанализировать)
  606.  
  607.             TasksApi.assertTasks(DEFAULT_TASKS[0], DEFAULT_TASKS[1], new Task("t3 title", "", false, TasksApi.uri + "/3"));
  608.             методу передаем ожидаемый результат
  609.             внутри метода - получаем список тасок и сверяем его
  610.             DEFAULT_TASKS - массив со значениями по умолчанию
  611.            
  612.             заметь - при проверке передаем в качестве третьей таски - новую таску с ожидаемо заполненными полями
  613.            
  614.         */
  615.         assertStatusCode(201);
  616.     }
  617.  
  618.     @Test
  619.     public void testCreateTaskWithoutParameters() {
  620.         /*
  621.             ну...
  622.             если решил проверить на Bad request
  623.             то стоит такие тесты написать для всех операций)
  624.             причем вариантов там много - думаю, стоит это делать глядя на код рест сервера
  625.            
  626.             но...
  627.             предлагаю таки этого не делать)
  628.            
  629.             первое, что нужно, чтобы рест-сервер корректно обрабатывал верные запросы)
  630.             давай сосредоточимся на первом)
  631.            
  632.             предлагаю ограничиться двумя методами для теста создания таски
  633.             testCreateWithFullInformation и testCreateWithTitle
  634.        
  635.         */
  636.         TaskWithoutTitle task = new TaskWithoutTitle();
  637.         response = authorized(requestTo(TestData.URL)).post(Entity.entity(task, MediaType.APPLICATION_JSON));
  638.  
  639.         assertError("Bad request");
  640.         assertStatusCode(400);
  641.     }
  642.  
  643.     @Test
  644.     public void testUpdate() {
  645.         List<Task> receivedTasks = getAllTasks();
  646.         Task lastTask = receivedTasks.get(receivedTasks.size()-1);
  647.         lastTask.setTitle(lastTask.getTitle() + " edited");
  648.         lastTask.setDone(true);
  649.         lastTask.setDescription(lastTask.getDescription() + " edited");
  650.         /*
  651.             вот эта логика реально лишняя
  652.            
  653.             у нас же гарантированно на начало теста - 2 такие-то таски
  654.             ты знаешь какие
  655.             все их данные зашиты в тестовых данных
  656.            
  657.             ты можешь создать
  658.              Task task = new Task("t2 title", "t2 description", true, TasksApi.uri + "/2");
  659.            
  660.             и выполнить апдейт таски. ее URI мы уже задали
  661.            
  662.             а дальше - достаточно проверки с помощью все того же метода assertTasks
  663.         */
  664.  
  665.  *******************************************
  666. Есть костыль вроде создания класса таски без поля tile -
  667. другого решения не нашел как проверить что это поле обязательное
  668. /*
  669.     предлагаю уйти от этого)
  670.     выше писала
  671. */  
  672. (null подставляется когда использую с пустым конструктором)
  673. /*
  674.     ничего не мешает в конструкторе без параметров предзаполнить поля значениями по умолчанию = пустыми строками
  675. */  
  676.  
  677. В некторых местах скрыта тестовая логика, еще буду думать как это исправить.
  678. Так же в некоторых местах для верификации тасок использую сравнение всех атрибутов
  679. вместо метода assertTasks (опять же это из-за того что скрыта тестовая логика)
  680. /*
  681.     надеюсь, описание позволит распутать это)
  682.    
  683.     ревью длинное и не простое)
  684.    
  685.     думаю, ты избежал бы многих проблем и вопросов,
  686.     если бы это делал уже после работ по селениуму
  687.     при написании фреймворка многое бы разобрали - общие принципы в том числе)
  688.    
  689.     но ты не расстраивайся.
  690.     ок
  691.     начали с этой работы
  692.     значит - работы по селениуму будет потом делать легче)
  693.     ведь часть общих принципов разберем тут
  694. */
Advertisement
Add Comment
Please, Sign In to add comment