Add test, log MARTYNOV Pantera#6
Conversation
Change pom.xml
demologin
left a comment
There was a problem hiding this comment.
Общий вывод по проекту
Проект представляет собой добротную базу для веб-приложения на сервлетах. Основные сильные стороны: использование современного стека (Java 21, JUnit 5, Mockito, SLF4J), наличие логирования и попытка реализовать глобальную статистику через ServletContext.
Основные зоны роста:
Архитектура: Сервлет сейчас выполняет роль «божественного объекта» (God Object). Вынесение логики квеста в сервисный слой сделает код более тестируемым и чистым.
Масштабируемость: Использование switch-case для шагов квеста быстро станет проблемой. Изучение паттернов проектирования (State, Strategy) поможет сделать структуру гибкой.
Тестирование: Тесты написаны грамотно, но стоит уделить внимание расположению пакетов.
Это отличный старт! Видно, что вы уделяете внимание деталям и стремитесь использовать профессиональные инструменты. Продолжайте изучать SOLID и паттерны проектирования — они помогут вам превратить этот проект в по-настоящему гибкую и мощную систему. Удачи в изучении Java!
Итоговая оценка: B
| import java.util.concurrent.ConcurrentHashMap; | ||
|
|
||
| @WebServlet(name = "QuestServlet", value = "/quest") | ||
| public class QuestServlet extends HttpServlet { |
There was a problem hiding this comment.
Класс нарушает принцип единственной ответственности (SRP). Он управляет сессиями, логикой игры и статистикой. Рекомендуется выделить бизнес-логику в класс GameService. [ERROR]
| int currentStep = state.getStep(); | ||
| String name = state.getPlayerName(); | ||
|
|
||
| switch (currentStep) { |
There was a problem hiding this comment.
Использование switch-case для описания шагов квеста делает код 'жестким'. Рекомендуется использовать паттерн 'State' или загрузку сценария из внешнего JSON-файла. [WARNING]
| @Override | ||
| public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { | ||
| HttpSession session = req.getSession(); | ||
| GameState state = (GameState) session.getAttribute("state"); |
There was a problem hiding this comment.
Потенциальный NullPointerException: извлечение атрибута 'state' из сессии без проверки на null. При истечении времени сессии это приведет к падению приложения. [ERROR]
| state.incrementGames(); | ||
| } | ||
|
|
||
| req.getRequestDispatcher("/quest.jsp").forward(req, resp); |
There was a problem hiding this comment.
Путь к JSP-файлу '/quest.jsp' захардкожен. Целесообразно вынести пути к представлениям в константы для упрощения рефакторинга. [INFO]
| } | ||
|
|
||
| ServletContext context = getServletContext(); | ||
| Map<String, UserStats> statsMap = (Map<String, UserStats>) context.getAttribute("globalStats"); |
There was a problem hiding this comment.
Хранение глобальной статистики в ServletContext (statsMap) не надежно. Данные будут утеряны при перезагрузке сервера. Стоит рассмотреть использование БД. [WARNING]
| import jakarta.servlet.ServletContext; | ||
| import jakarta.servlet.ServletException; | ||
| import jakarta.servlet.annotation.WebServlet; | ||
| import jakarta.servlet.http.HttpServlet; |
There was a problem hiding this comment.
Сервлет не хранит состояние в полях класса, что делает его безопасным для использования в многопоточной среде Java EE. [INFO]
| this.deathReason = deathReason; | ||
| } | ||
|
|
||
| public void resetGame() { |
There was a problem hiding this comment.
Метод resetGame корректно сбрасывает текущий шаг, но сохраняет накопленную статистику побед, что удобно для игрока. [INFO]
| } else if ("answer".equals(action)) { | ||
| String choice = req.getParameter("choice"); | ||
| logger.debug("Player '{}' made a choice: {} on step {}", state.getPlayerName(), choice, state.getStep()); | ||
| processGameStep(state, choice); |
There was a problem hiding this comment.
Прямое управление полем step объекта GameState из сервлета нарушает инкапсуляцию. Лучше реализовать метод state.moveToNextStep(). [WARNING]
| import org.junit.jupiter.api.extension.ExtendWith; | ||
| import org.mockito.Mock; | ||
| import org.mockito.InjectMocks; | ||
| import org.mockito.junit.jupiter.MockitoExtension; |
There was a problem hiding this comment.
Использование Mockito для имитации объектов контейнера сервлетов — правильный путь для изоляции тестируемого компонента. [INFO]
|
|
||
| assertEquals(2, state.getStep(), "После выбора 'trust' на 1 шаге, текущий шаг должен быть 2"); | ||
|
|
||
| verify(dispatcher, times(1)).forward(request, response); |
There was a problem hiding this comment.
Тест проверяет вызов forward, что гарантирует правильное завершение жизненного цикла запроса в сервлете. [INFO]
Change pom.xml