diff --git a/MtdrSpring/backend/src/test/java/com/springboot/MyTodoList/bot/TaskStatusHandlerTest.java b/MtdrSpring/backend/src/test/java/com/springboot/MyTodoList/bot/TaskStatusHandlerTest.java new file mode 100644 index 000000000..a164e17e9 --- /dev/null +++ b/MtdrSpring/backend/src/test/java/com/springboot/MyTodoList/bot/TaskStatusHandlerTest.java @@ -0,0 +1,47 @@ +package com.springboot.MyTodoList.bot; + +import com.springboot.MyTodoList.TestFixtures; +import com.springboot.MyTodoList.task.TaskService; +import com.springboot.MyTodoList.telegram.handler.TaskStatusHandler; +import com.springboot.MyTodoList.user.UserService; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; +import org.mockito.Answers; +import org.telegram.telegrambots.meta.api.methods.send.SendMessage; +import org.telegram.telegrambots.meta.api.objects.Update; +import org.telegram.telegrambots.meta.generics.TelegramClient; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +class TaskStatusHandlerTest { + + @Mock UserService userService; + @Mock TaskService taskService; + @InjectMocks TaskStatusHandler handler; + + @Test // Test #17 + void handle_invalidStatus_sendsValidStatusListError() throws Exception { + Long chatId = 12345L; + // Deep stubs evitan importar la clase Message interna del SDK de Telegram + Update update = mock(Update.class, Answers.RETURNS_DEEP_STUBS); + TelegramClient client = mock(TelegramClient.class); + + given(update.getMessage().getChatId()).willReturn(chatId); + given(update.getMessage().getText()).willReturn("/task_status 200 INVALID_STATUS"); + given(userService.findByTelegramChatId(chatId)).willReturn(TestFixtures.user(1L)); + + handler.handle(update, client); + + verify(client).execute(any(SendMessage.class)); + } +} diff --git a/MtdrSpring/backend/src/test/java/com/springboot/MyTodoList/notification/NotificationServiceTest.java b/MtdrSpring/backend/src/test/java/com/springboot/MyTodoList/notification/NotificationServiceTest.java new file mode 100644 index 000000000..1fac71d5c --- /dev/null +++ b/MtdrSpring/backend/src/test/java/com/springboot/MyTodoList/notification/NotificationServiceTest.java @@ -0,0 +1,51 @@ +package com.springboot.MyTodoList.notification; + +import com.springboot.MyTodoList.TestFixtures; +import com.springboot.MyTodoList.user.User; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; +import org.telegram.telegrambots.meta.api.methods.send.SendMessage; +import org.telegram.telegrambots.meta.generics.TelegramClient; + +import java.lang.reflect.Field; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +class NotificationServiceTest { + + @Mock TelegramClient telegramClient; + @Mock NotificationLogRepository notificationLogRepository; + + NotificationService notificationService; + + @BeforeEach + void setUp() throws Exception { + notificationService = new NotificationService(notificationLogRepository); + // telegramClient es @Autowired(required=false) — no está en el constructor de Lombok + Field field = NotificationService.class.getDeclaredField("telegramClient"); + field.setAccessible(true); + field.set(notificationService, telegramClient); + } + + @Test // Test #16 + void send_taskBlocked_sendsMessageToManagerViaTelegram() throws Exception { + User manager = TestFixtures.user(1L); + manager.setTelegramChatId(99999L); + + given(notificationLogRepository.save(any())).willAnswer(i -> i.getArgument(0)); + + notificationService.send(manager, "TASK_BLOCKED", "Task 'Fix login' was blocked"); + + verify(telegramClient).execute(any(SendMessage.class)); + verify(notificationLogRepository).save(any()); + } +} diff --git a/MtdrSpring/backend/src/test/java/com/springboot/MyTodoList/task/TaskRequestValidationTest.java b/MtdrSpring/backend/src/test/java/com/springboot/MyTodoList/task/TaskRequestValidationTest.java new file mode 100644 index 000000000..147f277d6 --- /dev/null +++ b/MtdrSpring/backend/src/test/java/com/springboot/MyTodoList/task/TaskRequestValidationTest.java @@ -0,0 +1,48 @@ +package com.springboot.MyTodoList.task; + +import com.springboot.MyTodoList.common.enums.TaskStatus; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +class TaskRequestValidationTest { + + private static Validator validator; + + @BeforeAll + static void setup() { + validator = Validation.buildDefaultValidatorFactory().getValidator(); + } + + @Test // Test #10 + void taskName_blank_failsValidation() { + TaskRequest req = new TaskRequest(); + req.setTaskName(""); + req.setStatus(TaskStatus.TODO); + req.setStoryPoints(1); + + Set> violations = validator.validate(req); + + assertThat(violations) + .anyMatch(v -> v.getPropertyPath().toString().equals("taskName")); + } + + @Test // Test #12 + void taskName_onlyEmojis_passesValidation() { + TaskRequest req = new TaskRequest(); + req.setTaskName("🚀🎯💡"); + req.setStatus(TaskStatus.TODO); + req.setStoryPoints(1); + + Set> violations = validator.validate(req); + + assertThat(violations) + .noneMatch(v -> v.getPropertyPath().toString().equals("taskName")); + } +} diff --git a/MtdrSpring/backend/src/test/java/com/springboot/MyTodoList/task/TaskServiceTest.java b/MtdrSpring/backend/src/test/java/com/springboot/MyTodoList/task/TaskServiceTest.java index b4ce25e21..b289de611 100644 --- a/MtdrSpring/backend/src/test/java/com/springboot/MyTodoList/task/TaskServiceTest.java +++ b/MtdrSpring/backend/src/test/java/com/springboot/MyTodoList/task/TaskServiceTest.java @@ -4,6 +4,7 @@ import com.springboot.MyTodoList.audit.AuditLogService; import com.springboot.MyTodoList.common.enums.ActivityType; import com.springboot.MyTodoList.common.enums.SprintStatus; +import com.springboot.MyTodoList.common.enums.TaskPriority; import com.springboot.MyTodoList.common.enums.TaskStatus; import com.springboot.MyTodoList.common.exception.ClosedSprintException; import com.springboot.MyTodoList.common.exception.ForbiddenException; @@ -73,6 +74,56 @@ void setUp() { given(taskMapper.toResponse(any())).willReturn(new TaskResponse()); } + // --- createTask: happy path (#6) --- + + @Test + void createTask_withAllFields_savesAndReturnsResponse() { + given(userService.findActiveUserById(1L)).willReturn(manager); + given(projectService.findProject(10L)).willReturn(project); + given(sprintRepository.findById(100L)).willReturn(Optional.of(activeSprint)); + given(userService.findActiveUserById(2L)).willReturn(member); + given(taskRepository.save(any())).willReturn(task); + + TaskRequest req = new TaskRequest(); + req.setTaskName("Implementar login"); + req.setDescription("Descripción de la tarea"); + req.setStatus(TaskStatus.TODO); + req.setPriority(TaskPriority.HIGH); + req.setStoryPoints(3); + req.setAssignedTo(member.getId()); + req.setSprintId(activeSprint.getId()); + + TaskResponse result = taskService.createTask(manager.getId(), project.getId(), req); + + assertThat(result).isNotNull(); + verify(taskRepository).save(any(Task.class)); + verify(auditLogService).log(any(), any(), any(), any(), any(), any()); + } + + // --- updateTask: happy path (#7) --- + + @Test + void updateTask_changesTitlePriorityAndSprint() { + Sprint newSprint = TestFixtures.sprint(101L, project, SprintStatus.PLANNING); + given(userService.findActiveUserById(1L)).willReturn(manager); + given(projectService.findProject(10L)).willReturn(project); + given(sprintRepository.findById(101L)).willReturn(Optional.of(newSprint)); + given(taskRepository.save(any())).willReturn(task); + + TaskRequest req = new TaskRequest(); + req.setTaskName("Nuevo título"); + req.setPriority(TaskPriority.LOW); + req.setStatus(TaskStatus.TODO); + req.setStoryPoints(2); + req.setSprintId(newSprint.getId()); + + TaskResponse result = taskService.updateTask(manager.getId(), project.getId(), task.getId(), req); + + assertThat(result).isNotNull(); + verify(taskRepository).save(any(Task.class)); + verify(auditLogService).log(any(), any(), any(), any(), any(), any()); + } + // --- changeStatus: DONE validation --- @Test