Progress28.ru

IT Новости


09ae9cb0
3 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Разработка web приложений на java

Создаём веб-приложение с Java Servlets

  • Переводы, 18 марта 2018 в 14:35
  • Никита Прияцелюк

Одной из самых приятных особенностей Java является её многогранная природа. Конечно, создание традиционных десктопных и даже мобильных приложений — это здорово. Но что, если вы хотите уйти с проторенных дорожек и зайти на территорию разработки web приложений на Java? Для вас есть хорошая новость: в комплекте с языком идёт полноценный Servlet API, который позволяет вам создавать надёжные веб-приложения без особых хлопот.

Это статья для продолжающих. Если вы только начинаете знакомство с Java, советуем пройти быстрый старт, посмотреть видеокурс и выбрать одну из книг для новичков.

Создание приложений на Java с помощью Servlets

Встречайте сервлеты, особый тип Java-программ, выполняемый в пределах веб-контейнера (также называемый контейнером сервлетов, как, например, Tomcat и Jelly), которые позволяют обрабатывать запросы клиентов и ответы сервера просто и эффективно. Сейчас не время и не место дотошно объяснять вам, что из себя представляет сервлет. Достаточно сказать, что сервлеты создаются и уничтожаются их контейнерами, а не разработчиком, и действуют как промежуточный уровень между клиентами (как правило, веб-браузерами) и другими приложениями, запущенными на сервере (например, базами данных).

Сервлет — классная штука, которая помимо всего прочего может принимать данные от клиента, как правило через GET и POST-запросы, работать с cookie и параметрами сеанса. А ещё она обрабатывает данные через дополнительные уровни приложений и отправляет выходные данные клиенту как в текстовом, так и в бинарном форматах (HTML, XML, PDF, JPG, GIF и т.д.), во многих случаях используя Java Server Pages (JSP) файлы.

Лучше всего начинать работу с сервлетами через конкретный пример. Мы создадим простое веб-приложение, которое позволит клиентам регистрироваться с помощью простой HTML-формы. Данные, предоставленные клиентами, будут собираться сервлетом и проверяться валидаторами.

Разбираемся с конфигурационными файлами

Чтобы вы понимали структуру нашего будущего приложения, вот как она будет выглядеть:

Первым шагом к созданию приложения является определение так называемого дескриптора развёртывания. Он указывает, как приложение должно быть развёрнуто в определенной среде. Когда дело касается веб-приложений, дескриптор развёртывания представляет собой простой XML-файл, называемый web.xml и является частью стандартной спецификации Java EE. В нашем случае он будет выглядеть так:

Как вы видите, web . xml только определяет версию Java Servlet Specification (3.1), которую мы будем использовать в приложении. Разумеется, в нём может быть гораздо больше содержимого, включая директивы сопоставления сервлетов, параметры инициализации, список приветственных файлов и несколько дополнительных настроек. Но чтобы не усложнять процесс разработки, давайте оставим его таким как есть.

LATOKEN, Москва, от 3500 до 5000 $

Так как наше приложение будет использовать Servlet API и Java Servlet Pages (JSP) для отображения данных клиента, нам нужно загрузить все необходимые JAR. Maven сделает за нас трудную работу, вот как будет выглядеть файл POM:

Если говорить просто, pom.xml определяет все зависимости, необходимые для работы с сервлетами: JSP, Java Standard Tag Library (JSTL) и Java Expression Language (JEL).

Итак, мы уже создали конфигурационные файлы приложения. Однако в текущем состоянии оно буквально ничего не делает. Мы хотим, чтобы клиенты могли регистрироваться с помощью HTML-формы, поэтому следующее, что нам нужно сделать, — это создать JSP-файлы, которые будут отображать вышеупомянутую форму и данные клиента после успешного завершения регистрации. Этим мы сейчас и займёмся.

Работаем над внешним видом

Внешний вид приложения будет определяться двумя JSP-файлами — в контексте MVC они называются представлениями. Первый будет отвечать за отображение формы регистрации и возможных ошибок, вызванных после проверки введённых данных. Второй будет обычной страницей приветствия, в которой будут показаны данные, введённые клиентом, после успешного завершения процесса регистрации.

Вот первый JSP-файл:

Файл содержит простой HTML с парочкой дополнений. Вот она, прелесть JSP в сочетании с JSTL и JEL. Обратите внимание на то, как легко проверить наличие ошибок валидации, используя такие стандартные теги, как и .

Атрибут формы регистрации action указывает на следующий URL: $/processcustomer . Это значит, что каждый раз, когда клиент пытается зарегистрироваться, данные будут отправляться в processcustomer независимо от URL, по которому доступна форма. Это достигается за счёт функциональности объектов, доступных из JSP-файла, таких как request .

Скоро мы увидим, как сервлет связывается с URL processcustomer и как он взаимодействует с введёнными данными. А пока давайте посмотрим на JSP-файл, который отвечает за страницу приветствия:

Теперь, когда мы разобрались с отображением страниц, следующим шагом будет создание сервлета, ответственного за сбор данных клиента из POST-запросов и подтверждение данных простым способом.

Пишем контроллер

Написать сервлет, способный получить данные из формы регистрации, проще простого. Всё, что нам нужно сделать, — это написать подкласс для класса HttpServlet и реализовать его методы doGet() или doPost() (или оба, если надо). В данном случае сервлет будет взаимодействовать с данными, поступающими из POST-запросов.

Вот как он выглядит:

Первое, на что здесь стоит обратить внимание, — использование аннотации @WebServlet(name =»CustomerController», urlPatterns = «/processcustomer») . Она говорит контейнеру сервлета использовать класс CustomerController для обработки HTTP-запросов по адресу /processcustomer . Того же эффекта можно достичь путём добавления директив сопоставления сервлетов в web.xml , как здесь, но так как мы используем Servlet Specification 3.1 нам нет необходимости прибегать к такому способу.

Здесь мы назвали сервлет CustomerController , так как считается хорошей практикой использовать имя класса сервлета в качестве значения атрибута name аннотации @WebServlet . В противном случае некоторые контейнеры не смогут выполнить сопоставление, что приведёт к ошибке 404.

Сам класс CustomerController выполняет несколько простых задач. Во-первых, он собирает введённые в форму данные, используя реализацию интерфейса HttpServletRequest , который содержит значения, соответствующие полям firstname , lastname и email формы. Затем он устанавливает эти значения в качестве атрибутов запроса, поэтому их можно повторно отобразить либо в форме, либо на странице с результатами. Наконец, валидаторы проверяют правильность введённых данных.

Валидаторы — это простые классы, которые проверяют определённые свойства, например, является ли строка пустой и выглядит ли email как email. На GitLab автора можно посмотреть на их реализацию.

Результат валидации влияет на дальнейший ход событий: если данные не валидны, клиент перенаправляется через объект RequestDispatcher на страницу регистрации, где отображаются соответствующие ошибки. Если всё в порядке, то отображается страница приветствия.

Итак, мы создали целое веб-приложение на Java, которое позволяет зарегистрировать клиентов с помощью HTML-формы, базового сервлета и нескольких JSP-файлов. Пора его запустить.

Запускаем приложение

Для запуска приложения нужно проделать следующие шаги:

  1. Для начала нам понадобится Git (убедитесь, что скачиваете подходящую версию), Maven и контейнер сервлета (например, Apache Tomcat, Jetty, или JBoss Wildfly). Если что-то из этого уже включено в вашу IDE, то вы можете использовать встроенный вариант.
  2. Используйте Git, чтобы клонировать репозиторий приложения, и импортируйте его в вашу IDE, желательно как проект Maven.
  3. Разверните проект в контейнере сервлета и запустите его. Развёртывание подразумевает создание WAR-файла или exploded WAR и его помещение в папку развёртывания контейнера по умолчанию. Зачастую IDE способна сделать развёртывание за вас, поэтому не перегружайте себя лишней работой и посмотрите документацию вашей IDE (документация для IntelliJ IDEA). Когда вы развернёте проект и запустите его, должен запуститься бразуер по умолчанию с окном регистрации.
  4. Попробуйте заполнить не все поля в форме или вовсе не заполнить их и вы увидите, как поверх соответствующих полей отобразятся ошибки. Введите всё как положено, и вас перенаправит на страницу приветствия.

Заключение

Итак, вы приобрели все навыки, необходимые для создания собственного веб-приложения на Java без необходимости прибегать к сложным фреймворкам. Всё, что вам нужно, — Servlet API, технология вроде JSP для отображения и встроенные средства Java. Здорово, правда?

Стоит отметить, что реализация класса CustomerController подчеркивает достоинства и недостатки сервлетов: с одной стороны, он вкратце показывает, насколько легко обрабатывать параметры запроса и отправлять ответы клиенту в разных форматах. Но эта функциональность имеет свою цену: обе реализации интерфейсов HttpServletResponse и HttpServletResponse являются обычными локаторами служб. Нельзя сказать, что это плохо, поскольку локаторы просто содержат данные. Однако нужно помнить, что эти реализации будут всегда привязаны к сервлету.

Пошаговая разработка веб-приложения

При устройстве на работу java программистом меня попросили написать тестовое web приложение «Телефонный справочник». Хочу поделиться с вами этим «шедевром».

Вид и функциональность приложения






Инструменты

Создание проекта

Укажите путь к Java в Project SDK.


Укажите путь к своей Maven home directory.



«Maven projects need to be imported» кликаем Enable Auto-Import.

Добавим Tomcat Server.



В Application server укажите путь до Tomcat сервера.




Ok -> Apply -> Ok

Проверим, что всё работает.



Клиент (ExtJS)

Добавим файлы фрэймворка.

Модель ExtJS MVC.

Создадим файл app.js

  • Метод Ext.application инициализирует приложение Ext JS;
  • name: ‘PhonesDir’ указывает имя приложения, которое будет затем использоваться для создания полных имен классов приложения;
  • appFolder: ‘app’ указывает на нашу папку с инфраструктурой приложения (controller, model, store, view);
  • launch: function()<> тут происходит создание приложения.

В файле index.jsp подключаем стили ExtJS, затем фреймворк ExtJS и только потом app.js:

Проверим, что всё работает.

Нам понадобится четыре вида — это вид поиска SearchPhones.js, вид таблицы PhoneGrid.js, вид формы добавления данных AddWindowForm.js и вид каркаса PhonesDirectory.js, куда мы поместим все виды.

Изменим параметр items в app.js.

  • phonesDirectory’ алиас, который мы указали в параметре alias в PhoneDirectory.js.
  • Метод Ext.define(‘Имя’, <параметры>) создает класс-компонент, который может быть унаследован от какого-нибудь компонента. Например в PhoneGrid.js указали extend: ‘Ext.grid.Panel’, что будет представлять собой таблицу.
Controller

Виды загружаются из контролера, поэтому создадим контролер PhonesDirectoryControoler.js и укажим его в app.js

  • С помощью параметра init инициализируются обработчики для компонентов (кнопки, поля и т.д). Связать конпонент с обработчиком помогает функция control.

Конечная структура app.js

Проверим, что всё работает.

Модель и хранилище

  • pageParam: ‘search’ нужен для реализации логики поиска на сервере. В нём будут находится данные из поля поиска и, если не пусто, сервер выполнит выборку данных из БД , иначе вернет все данные.
  • ‘phone’ имя, на которое будет замапен java-класс (контролер), который будет обрабатывать GET, POST, DELETE запросы с клиента.

Добавим модель PhonesDirectoryModel.js и хранилище PhonesDirectoryStore.js в контролер PhonesDirectoryController.js

Добавим в PhonesGrid.js параметр store: ‘PhonesDirectoryStore’, для отображения данных в таблице.

Проверим, что всё работает. 404 (Not Found) — это нормально, так как по адресу localhost:8080/phone еще ничего нет.

Сервер (Java)

Создадим папку java:

Создадим модель данных и слой доступа к данным (DAO)

  • Метод getPhones(String search) принимает значение параметра, которого мы указали в PhonesDirectoryModel.js;
  • Метод findByPhone(String name, String phone) используется для поиска дубликата при добавлении данных.

Создадим слой сервиса:

Создадим контролер, который будет замапен на адрес /phone для обработки запросов с клиента.

  • Каждый метод замапен на соответствующий запрос с клиента. Внедряем зависимость с помощью spring аннотации @Autowired и вызывает соответствующие методы у сервиса;
  • ExtResult — вспомогательный класс. Используется для ответа клиенту, что сущность, которую пытаемся записать в БД , дубликат или не дубликат.

Проверьте, что всё работает. Соберите проект с помощью maven install и запустите приложение.

Создадим spring контекст my-context.xml c:

  • настройками подключения к БД;
  • бином EntityManager — объект, через который происходит взаимодействие с БД. Инжектится в PhoneDaoImpl.java;
  • инжектом объекта класса PhoneDaoImpl.java в объект класса PhoneServiceImpl.java.

Создайте БД с названием phonedir или измените название в контексте на своё.

Создадим настройки для spring DispatcherServlet, который будет обрабатывать запросы с клиента.

  • context:component-scan поиск и регистрация компонентов в контейнере спринга;
  • mvc:view-controller домашняя страница;
  • mvc:resources автоматически обрабатывать запросы на получение статических данных.

Добавим spring контекст my-context.xml и настройки для spring DispatcherServlet в дескриптор развертывания web.xml

Добавим в контролер PhonesDirectoryController.js параметр refs и обработчики для компонентов.

  • ref ссылка на что-то в selector’e.
  • selector указывает на компоненты, для быстро обращения к ним через ref.
  • onSavePhone создается модель данных и сохраняется.
  • onAddPhone создает виджет формы добавления.
  • onDelPhone удаляет запись.
  • onChangeText загружает данные в соответствии со значением в поле поиска.
  • onLineGrid при выделении строки кнопка «Удалить» становится активной
  • onValidation валидация полей формы добавления.

И последнее — добавим иконки к кнопкам «Добавить» и «Удалить»:

WEB приложение на Java

Вы наверняка слышали о том, что сайты можно делать на PHP, Python и довольно не плохие сайты. Но как же Java? Да на java тоже можно делать очень даже офигенные сайты, а если быть точней то используют java для разработки крупных ресурсов. В этом уроке я покажу как создать простое web-приложение на java.

Что нам потребуется для создания web-приложения?

1) Любой сервер приложений в нашем случае это будет Tomcat 7.0.

2) Верная и надежная Intellij IDEA.

3) Желание создать своё первое WEB-приложение.

Шаг 1

Создаем обычный Maven проект, назовем его MyFirstWebProject. Структура проекта следующая:

Давайте теперь разберем структуру проекта: src/java/ servlets – тут будут лежать сервлеты(сервлеты будут рассматриваться в Шаг 2.) src/ resources – тут будут лежать все ресурсные файлы которые буду нужны для проекта. src/ webapp – тут лежат все файлы которые будут использоваться во view (к примеру img, css).

Шаг 2

Теперь разберем что такое Servlet? Servlet – это Java-интерфейс, реализация которого расширяет функциональные возможности сервера. Servlet взаимодействует с клиентами посредством принципа запрос-ответ за частую это запросы GET, POST по протоколу HTTP/HTTPS. Для создания сервлета нам нужно подключить зависимости в Maven.

А также не забудьте указать:

это говорит Maven-у что собирать надо в WEB проект, по умолчанию он собирает jar.

Теперь нужно добавить 2 плагина который позволяет откомпилировать и собрать проект в war архив.

Полный листинг pom.xml:

Теперь создадим класс MyServlet который унаследуем от HttpServlet.

Как вы видите тут есть два метода doPost и doGet, как я уже упоминал сервлеты взаимодействуют с клиентом по средством запрос-ответ, так вот в основном это GET и POST. Внимание! Главное не допускать такую ошибку, что всего есть два метода GET/POST их на самом деле 9, это OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT, PATCH. И так рассмотрим эти методы методы: Как вы уже поняли метод doPost принимает и отправляет посредством запроса POST, doGet по средством запроса GET. У обоих методов есть входящие параметры типы которых – HttpServletRequest и HttpServletResponse. HttpServletRequest request – это запрос со стороны клиента; HttpServletResponse response – это ответ со стороны сервера.

Аннотация @WebServlet(“/s”) указывает на то что данный сервлет будет доступен по адресу /s.

Шаг 3

Не забываем, что метод GET срабатывает когда мы просто заходим по URL на страничку, а пост чаще всего используется при передачи данных с формы, но при условии что метод передачи данных формы указан POST. Создадим “Hello Word”:

response.setContentType(«text/html») – в этой строке мы говорим про то что отображать мы будем страничку как html. PrintWriter out = response.getWriter() – тут мы создаем врайтер который поможет нам осуществить ответ с сервера. out.println(«Hello Word») – ну и отправляем ответ с сервера клиенту.

Шаг 4

Теперь соберите проект в Maven:

Шаг 5

Установка и настройка Tomcat 7.0.

2. Извлекаем с архива;

3. Настроить Intellij IDEA что бы деплоить приложение на сервер с нее.

Нажимаем плюсик выбираем Tomcat Server -> Local после чего нажимаем Configure… и выбираем корневую папку где лежит Tomcat 7.0.

В Startup Page – указываем стартовую страничку загрузки в нашем случае это localhost:8080/s (где s это наш про аннотированиый сервлет).

Дальше заходим во вкладкуDeployment:


И выбираем ваш собранный проект, лежит он в корне проекта в папке target/ .war

Шаг 6

Завяжем на наш сервлет jsp страничку.

Для этого мы должны создать в папке src/main/webapp нашу страничку, в нашем случае это index.jsp.

И теперь с помощью метода GET отправим на нее тот же текст “

Hello World!

Вот так будет выглядеть наш метод сервлета doGet():

С помощью RequestDispatcher мы отправляем наш response request клиенту.

А так будет выглядеть index.jsp

С помощью конструкции $ мы принимаем данные с сервера.

После этого вы получите ту же по виду страничку, только это уже будет не сервлет отображать а jsp.

Для получения углубленных знаний по Java проходите наш курс «Программирование на языке Java для начинающих», а также читайте серию статей «Spring Data JPA. Работа с БД»: часть 1, часть 2 и часть 3

Начало разработки веб-приложений с Java и Spring

В этом цикле статей я опишу процесс разработки веб-приложения на Java и Spring на примере разработки простого интеренет-магазина. Цикл статей разбит таким образом, чтобы в каждой статье описывался процесс работы с одной технологией или с одной группой взаимосвязанных технологий.

Список статей цикла (будет обновляться):

  • Начало разработки веб-приложений с Java и Spring
  • Асинхронные запросы и REST
  • Spring и работа с базами данных
  • Управление доступом в веб-приложениях с Spring Security

Подготовка проекта

Как уже было написано выше, в статье я буду разбирать процесс разработки простого интернет-магазина. Для разработки проекта я буду использовать Spring Boot, поскольку данный фреймворк позволяет разрабатывать приложения со Spring быстро, минимизируя время, затрачиваемое на конфигурирование контекста приложения, и минимизируя возможные конфликты зависимостей.

В рамках данной статьи потребуются следующие зависимости:

  • spring-boot-starter-web в качестве основы веб-приложения на Servlet API
  • spring-boot-starter-thymeleaf для интеграции Thymeleaf в качестве библиотеки шаблонизации
  • spring-boot-starter-test для тестов

pom.xml будет выглядеть примерно следующим образом:

Код pom.xml и остальных файлов в этой статье преднамеренно минимизирован, полная версия доступна в репозитории.

Разработка веб-приложения с архитектурой MVC

Главный элемент практически любого интернет-магазина — каталог товаров, давайте разработаем страницы списка товаров и описания товара.

Для начала создадим класс, описывающий товар — Product:

В подавляющем большинстве приложений мы получаем данные из источников данных при помощи специальных классов-репозиториев. Для списка товаров мы создадим простой класс-репозиторий, который будет хранить товары в списке:

Аннотация @Repository нужна для автоматической регистрации компонента класса ProductRepository в контексте приложения.

Теперь можем создать контроллер, который будет обрабатывать поступающие запросы — ProductController:

Аннотация @Controller тоже нужна для автоматической регистрации компонента класса ProductController в контексте приложения. Он будет создан и зарегистрирован в контексте автоматически при запуске приложения.

Регистрация компонентов приложения при помощи аннотаций не является самой оптимальной с точки зрения эффективности использования ресурсов, но позволяет конфигурировать контекст приложения более наглядно.

Аннотация @RequestMapping указывает, что данный класс-контроллер обрабатывает HTTP-запросы, путь которых начинается с /catalog/products.

Страница списка товаров

Теперь для страницы списка товаров создадим метод findAll в ProductRepository, который потребуется для получения всех товаров из репозитория:

В классе ProductController создадим метод, который будет обрабатывать запрос на получение страницы списка товаров:

Аннотация @GetMapping указывает, что метод list обрабатывает запросы к сегменту пути list. Полный путь, который обрабатывает этот метод, складывается из пути, указанного в аннотации @RequestMapping класса ProductController, и пути, указанного в @GetMapping метода. Таким образом метод list обрабатывает запросы с путём /catalog/products/list.

Аннотации @GetMapping, @PostMapping и т.д. являются упрощенными альтернативами аннотации @RequestMapping. Таким образом вместо @GetMapping можно написать @RequestMapping(method = RequestMethod.GET)

Метод list возвращает объект класса ModelAndView, который передаёт имя отображаемого шаблона, модель, содержащую список товаров в атрибуте product, и HTTP-статус 200 OK.

Теперь можно создать шаблон страницы. Мы указали, что метод list возвращает шаблон с именем catalog/products/list, соответственно, нам для этого необходимо в директории ресурсов создать структуру директорий templates/catalog/products и файл list.html в ней.

Директория templates в директории ресурсов является директорией по умолчанию для шаблонов в веб-приложениях, использующих Spring Boot. Вместо этой директории можно указать другое место при помощи настроек шаблонизатора, например для Thymeleaf — spring.thymeleaf.prefix

Шаблон страницы будет очень простым и будет содержать список ссылок на страницы товаров:

Вместо специфичных для Thymeleaf аттрибутов используются аттрибуты, начинающиеся с data-th-. Это позволяет не использовать XML-схему Thymeleaf. Например, для генерирования аттрибута href используется data-th-href вместо th:href.

Если мы заполним репозиторий тестовыми данными, запустим приложение (например, при помощи Maven: mvn spring-boot:run) и откроем страницу http://localhost:8080/catalog/products/list, то увидим примерно такую страницу:

Страница со списком товаров

Тестирование

Тестирование является важной и неотъемлемой частью разработки качественного ПО, оно позволяет ещё на этапе разработки отсеять большую часть возможных ошибок. Существует несколько способов тестирования, среди которых основные — модульное и интеграционное тестирование.

Как правило, различные способы тестирования являются взаимодополняющими, а не взаимоисключающими, даже если они они содержат одни и те же проверки.

Библиотека spring-boot-starter-test предоставляет богатый инструментарий для модульного и интеграционного тестирования приложений, использующих Spring. Никаких дополнительных зависимостей нам на данный момент не потребуется.

В модульных тестах каждый компонент тестируется изолированно, а поведение связанных компонентов имитируется. В интеграционных тестах тестируется поведение системы в целом, включая взаимодействие между компонентами.

В первую очередь давайте напишем модульный тест для метода list класса ProductController. Поскольку в данном методе отсутствуют ветвления, тест будет очень простой:

Я комментариями разделил код теста на три части: описание исходных условий (given), вызов тестируемого метода (when) и проверку результата (then). Каждый тест имеет минимум две части: вызов и проверку результата.

В части, где описываются исходные условия, я создал мок-объект для класса ProductRepository и указал, что должен вернуть его метод findAll. Я мог бы использовать реальный объект этого класса, но тогда это нарушало бы принцип изолированности тестирования, поскольку тест начал бы зависеть от поведения ProductRepository.

В части, где описываются проверки, я проверил полученный объект класса ModelAndView на соответствие нужным критериям при помощи статических методов класса Assert и проверил, что был вызван метод ProductRepository.findAll() при помощи метода Mockito.verify().

На этом написание модульного теста завершено. Если мы запустим тест, то он должен завершиться успешно. Теперь можно перейти к написанию интеграционного теста. В нём мы будем тестировать HTTP-вызов к нашему веб-приложению и проверять полученный ответ. Заготовка класса интеграционных тестов для приложения на основе Spring Boot выглядит следующим образом:

Для интеграционного тестирования нам понадобится MockMvс, при помощи которого будут имитироваться HTTP-вызовы к приложению. Мы можем создать этот объект самостоятельно, а можем отметить класс ProductControllerIntegrationTest аннотацией @AutoConfigureMockMvc, а затем внедрить объект класса MockMvc через свойство при помощи аннотации @Autowired. Аналогично нему мы внедрим объект класса ProductRepository, чтобы в рамках интеграционного теста можно было наполнить репозиторий тестовыми данными, но для него будем использовать аннотацию @SpyBean, которая позволит отслеживать вызовы его методов.

На практике лучше предпочитать внедрение зависимости через конструктор или set-метод вместо внедрения через свойство. Но при написании тестов допустимо внедрение зависимостей и через свойство.

Теперь в тестовом методе при помощи объекта класса MockMvc мы можем сымитировать HTTP-вызов и проверить валидность ответа от приложения. Интеграционный тест будет выглядеть следующим образом:

Как и в случае с модульным тестом, код разделён на все те же три части: исходные условия, обращение к тестируемому методу и проверка результата. Обращу внимание на то, что для XPath-проверок требуется, чтобы возвращённая страница была XML-валидной, иначе будет выброшена ошибка, связанная с парсингом документа.

Если требуется более детальное тестирование HTML-страниц, то лучше обратиться к WebDriver или HtmlUnit, для которых предусмотрена интеграция с MockMvc.

Я преднамеренно не стал описывать тесты для ProductRepository, так как этот класс существует только в качестве примера. Тесты репозиториев будут описаны в одной из следующих статей, в которых речь пойдёт о работе с реальными базами данных.

Страница с описанием товара

Теперь можно разработать страницу с описанием товара. Но на этот раз мы будем вести разработку через тестирование, иными словами мы сначала напишем тесты, а уже после этого напишем код, который будет проходить эти тесты.

Написание тестов

Логичнее начать с написания интеграционного теста, так как им мы охватываем сразу все компоненты приложения, задействованные при обработке вызова. Более того, условия прохождения интеграционных тестов описываются более «человеческим» языком, чем условия модульных тестов.

Обработка запроса на получение страницы с описанием товара может пойти по двум сценариями, и мы можем их описать:

  1. Если товар с запрашиваемым идентификатором существует, то должна быть отображена страница с описанием товара и со статусом 200 OK
  2. Если товар с запрашиваемым идентификатором не существует, то должна быть отображена страница с ошибкой и со статусом 404 Not Found

Мы можем протестировать оба сценария в одном тестовом методе, но удобнее будет написать для каждого сценария отдельный тестовый метод. Предполагается, что наш будущий метод должен обратиться к репозиторию ProductRepository для получения товара по идентификатору и, в зависимости от результата, вернуть соответствующую страница. Код тестовых методов будет выглядеть следующим образом:

Я вынес заполнение репозитория ProductRepository в отдельный метод, отмеченный аннотацией @Before, чтобы избежать дублирования кода. Теперь перед вызовом каждого тестового метода репозиторий будет заново заполняться тестовыми данными.

После написания интеграционных тестов код проекта стал не компилируемым, так как у класса ProductRepository нет метода findOneById. Таким образом мы определили будущую функциональность при помощи тестов.

Теперь пришло время написать модульные тесты, как и в случае с интеграционными их будет тоже два:

Я вынес объекты ProductRepository и ProductController в свойства класса ProductControllerTest, так как они используются во всех тестах. Кроме этого я решил использовать Optional, вместо проверок на null.

Реализация

Теперь можно правильно реализовать метод product в классе ProductController, после чего код должен стать снова компилируемым, а тесты проходить успешно.

Для доступа к переменной в пути используется аннотация @PathVariable, обратите внимание на то, что имя аргумента метода должно соответствовать имени, указанному в плейсхолдере пути, иначе его нужно указать в аттрибуте name аннотации @PathVariable.

И для прохождения интеграционных тестов необходимо создать два простых шаблона:

Теперь мы можем снова запустить приложение и перейти со страницы списка товаров на страницу описания конкретного товара.

Страница с описанием продукта

Читать еще:  Ошибка 651 модем или другое устройство
Ссылка на основную публикацию