Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import copy
- tasks_for_reset = copy.deepcopy(tasks)
- /*
- предлагаю import copy
- выполнить вначале кода
- там где и остальные импорты
- хотя - технически и так ок
- будет упорядоченнее
- */
- ********************
- def reset_tasks():
- ...
- return make_response(jsonify({'reset is completed': 'successfully'}), 205)
- /*
- можно вернуть get_tasks()
- получим результат - как и у собственно get_tasks()
- оба гет-запроса будут работать аналогично, насколько это возможно
- */
- ************************
- http://joxi.ru/Y2LXgYnfnKLq02
- /*
- вот еще источник проблем)
- если мы создаем первую таску (например, перед этим - все таски удалили)
- то получим проблему)
- не будет у нас предыдущего элемента)
- все же - если элементов в коллекции тасок нету - то у первой таски должен быть ид=1
- https://lancelote.gitbooks.io/intermediate-python/content/book/ternary_operators.html
- https://lancelote.gitbooks.io/intermediate-python/content/book/comprehensions.html (dict абстракции)
- http://www.diveintopython.net/native_data_types/index.html#odbchelper.dict
- */
- ****************************
- public class Helpers {
- /*
- это - по сути, аналог пейджа-модуля
- Теперь у нас будет пекедж не pages, a resources. А правила работы с таким классом - аналогичные.
- Поскольку мы работаем только с тасками - в имена методов-действий можно не включать слово Tasks
- Имена методов-проверок - по-прежнему указываем точно
- Логично было бы назвать класс Tasks (будем реализовывать как ресурс-модуль, а не ресурс-объект)
- И в коде потом можно без статического импорта писать
- Response response = Tasks.create(URI, "give lesson");
- Это было бы и наглядно, и на будущее - на случай, если в тесте появятся запросы к другим ресурсам
- Tasks - неплохое имя
- но у нас есть класс Task
- и можно сказать - что мы используем один термин для достаточно разных понятий….
- Можно в таком случае для класса-ресурса использовать TasksApi или TasksRest в таком случае…
- Но и Tasks - тоже неплохо…, но хуже)
- Можно пойти на эту уступку в принципе - код понятный, названия наглядные
- Уже по пути
- На реальном проекте обычно создают класс-ресурс (объект или модуль) не сразу, когда начали писать тесты.
- А позже - когда появится необходимость переиспользовать вспомогательные методы в разных тест-классах.
- Или если одни более квалифицированные члены команды разрабатывают класс-ресурс,
- а другие - используют для разработки тестов. Но или если так принято в данной команде)
- Т е - это делается обычно при необходимости. С пейджами - в общем аналогично.
- */
- ************************************
- public static final String URI = "http://localhost:5000/todo/api/v1.0/tasks";
- /*
- было бы совсем ок, если бы в Сonfiguration.baseUrl, в котором именно домен был сохранен
- что бы его можно было от случая к случаю реконфигурить...
- Ведь это как раз та часть урла - которая не принадлежит ресурсу - "http://localhost:5000/"
- и зависит от того на каком сервере/по-какому-адресу ресурс/веб-сервис задеплоен
- На самом деле, здесь есть несколько способов как лучше сделать
- Первый, если есть уверенность, что тебе не нужно будет одновременно/параллельно посылать запросы на разные урлы
- То тогда можно использовать Configuration.baseUrl - типа обычная глобальная переменная
- если нет, тогда лучше "ооп" подход, когда обьект-ресурс помнит свой базовый урл (доменную часть)
- который передается при создании через конструктор
- */
- **********************************
- public static Invocation.Builder requestTo(String uri) {
- public static Invocation.Builder authorized(Invocation.Builder requestBuilder) {
- /*
- По сути - это универсальные методы
- их лучше вынести из класса-ресурса
- в отдельный класс с универсальными методами
- а чтоб они точно были универсальными - передавай "miguel:python" как параметр в метод authorized
- что это - это credentials
- а класс уместно назвать например RestHelpers
- */
- ***************************
- private static Response response;
- ...
- public static int getResponseStatus() {
- return response.getStatus();
- }
- ...
- public static String getErrorAnswer() {
- return response.readEntity(ErrorContainer.class).getError();
- }
- ...
- /*
- ну, немного магии таки есть в таком решении - когда в переменной ресурса - сохраняется ответ
- и потом мы с ним работаем)
- не магическое решение - это чтобы сами методы - возвразщали response
- и в тест-методах - мы получили его в там объявленную переменную
- и его проверили
- я предлагаю тоже магическое решение
- но - оно здорово упростит нам жизнь
- потому и предлагаю
- */
- @Test
- public void testReadTasks() {
- getAuthorizedAccess();
- assertEquals(200, getResponseStatus());
- assertEquals(2, getTasksSize());
- assertEquals("Buy groceries", getTask(0).getTitle());
- }
- //вот - не магический вариант
- @Test
- public void testReadTasks() {
- Response response = Tasks.get();
- //его можно упростить до вот такого
- @Test
- public void testReadTasks() {
- List<Task> receivedTasks = Tasks.get();
- /*
- Правильный статус ответа на каждый из запросов - строго определенный
- И если мы будем проверять статут ответа в тест-методе - то надо об этом думать и вспоминать - какой статус в каких случаях верный
- И можно выкрутиться - проверять статус ответа в нутри степа, а возвращать собственно entity из запроса.
- Сразу пара потенциально полезных моментов)
- Если встроить проверку response кода прямо в сам степ
- Тут сразу появляется интересный нюанс
- Дело в том, что мы так спрячем тестовую логику внутрь степа, что не очень хорошо
- С другой стороны - эта проверка = само собой разумеющееся
- Эта проверка достаточно стандартная и всегда будет повторяться после вызова степа (если будет жить вне степа)
- А раз так - то почему бы и не спрятать?
- На самом деле - нет однозначного ответа на этот вопрос...
- Так - со спрятанной проверкой - код станет проще во всех тестах - но втанет до некоторой степени “магическим”
- Тут надо решать самостоятельно - как лучше )
- На твое усмотрение
- Еще момент
- В этих API тестах - самих тестов может быть не так уж и много -
- чтоб еще и заморачиваться над DRY кода...нужно и этот аспект учитывать
- Но если пойти этим путем = прятать в степе проверку статуса response, то код будет намного более удобным:
- У нас в тест-методах останется лишь проверка состояния тасок
- Что код сделает легче
- И немного магичнее )
- */
- ************************************
- public class RESTfulTasksTest {
- @Before
- public void resetBase(){
- authorized(requestTo(URI + "/reset")).get();
- }
- /*
- я бы в классе-ресурсе - реализовала метод reset()
- смотри - этот гивен - это часть тест логики
- как минимум нельзя прятать такое в предке тест-класса
- этот гивен на самом деле такой важный, что лучше вообще не скрывать его
- ни в каком базовом классе....
- его желательно "видеть" в самом тесте
- часто даже не стоит такие вещи в @Before выносить, не смотря на то что код будет не DRY
- но будет еще более явным и очевидным)
- Хотя в этом случае наверное с @Before будет таки лучше )
- а в классы с именем BaseTest - желательно выносить что-то такое что однозначно общее для всех тестов,
- какие-то настройки может конфигурационные, которые в контексте тест логики смысла не имеют
- и их не грех "скрыть с глаз долой"
- */
- *************************
- assertEquals("Buy groceries", getTask(0).getTitle());
- assertEquals("Learn Python", getTask(1).getTitle());
- /*
- У наших тасок - есть не только заголовок, но и другие свойства
- И при сравнении - это все должно быть сверено
- Поскольку после ресета - мы получаем заведомо оинаковые таски -
- можно в тест-классе объявить и инициализировать массив тасок DEFAULT_TASKS и его использовать
- С таким вынесением тестовых данных в переменные надо быть осторожным
- Важно - не надо тестовые данные объявлять в ресурс модуле (опять аналогия с пейджом - мы и там такого правила придерживались)
- Тут и правда есть смысл объявить эти данные
- Часто тестовые данные разумно оставлять в логике самих тестов - таким образом код тестов более очевидный. Пример - тудуэмвиси тесты
- */
- *********************************
- @Test
- public void testUpdate() {
- int id = 2;
- updateTask("updated description", true, "updated task", id);
- assertEquals(200, getResponseStatus());
- Task receivedTask = getResponseTask();
- assertEquals("updated description", receivedTask.getDescription());
- assertTrue(receivedTask.isDone());
- assertEquals("updated task", receivedTask.getTitle());
- assertEquals(Helpers.URI + "/" + id, receivedTask.getUri());
- }
- //или
- @Test
- public void testUpdate() {
- Task task = new Task("t2 title", "t2 description", true, TasksApi.uri + "/2");
- TasksApi.update(task);
- TasksApi.assertTasks(DEFAULT_TASKS[0], task);
- }
- /*
- сразу несколько моментов
- посмотри на информацию по этим линкам
- http://www.java2s.com/Tutorial/Java/0140__Collections/CheckingforEquality.htm
- http://www.javapractices.com/topic/TopicAction.do?Id=17
- http://javadevnotes.com/java-array-to-list-examples
- и мы сможем сравнивать - как таску с таской, так и список тасок со списком тасок - используя
- assertEquals
- А если реализуешь метод toString для класса Task - и сообщение об ошибке будет более информативным.
- После выполненного действия однозначно нужно проверить список тасок
- получить его и сверить с ожидаемыми значениями
- именно такая проверка - проверит логику работы, а не только правильность ответа
- нужно или нет проверять и таску, которую возвращает запрос при редактировании - это уже от разного зависит
- если это уже где-то контролируется - можно опустить
- а если нет - то лучше покрыть
- тоже - возможно - стоит скрыть такую проверку внутри TasksApi.update
- спорно, на самом деле)
- а может - внутри TasksApi.update - пусть проверяется только код ответа
- а в тест-методе - проверить возвращенную в ответе TasksApi.update таску
- и следом - список тасок тоже проверить
- наверное - так будет погибче и попрозрачнее
- надо будет - воспользуются результатом метода TasksApi.update и его проверят
- а не надо - так и пренебрегут
- все же методы класса-ресурса (как и пейджа)
- должны быть тоже достаточно гибкими
- */
Advertisement
Add Comment
Please, Sign In to add comment