Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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));
}
}
Original file line number Diff line number Diff line change
@@ -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());
}
}
Original file line number Diff line number Diff line change
@@ -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<ConstraintViolation<TaskRequest>> 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<ConstraintViolation<TaskRequest>> violations = validator.validate(req);

assertThat(violations)
.noneMatch(v -> v.getPropertyPath().toString().equals("taskName"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
Loading