test: add NotificationServiceTest unit test

This commit is contained in:
5803024019 2026-05-15 21:37:55 +07:00
parent 70487e6d0d
commit 42543c27df

View File

@ -0,0 +1,197 @@
package com.walkguide.service;
import com.walkguide.dto.request.SendNotificationRequest;
import com.walkguide.dto.response.NotificationResponse;
import com.walkguide.entity.GuardianNotification;
import com.walkguide.entity.PairingRelation;
import com.walkguide.entity.User;
import com.walkguide.enums.NotificationType;
import com.walkguide.enums.PairingStatus;
import com.walkguide.exception.PairingException;
import com.walkguide.repository.GuardianNotificationRepository;
import com.walkguide.repository.PairingRelationRepository;
import com.walkguide.websocket.LocationBroadcaster;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
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.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import java.util.List;
import java.util.Optional;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
@DisplayName("NotificationService Unit Tests")
class NotificationServiceTest {
@Mock GuardianNotificationRepository notifRepository;
@Mock PairingRelationRepository pairingRelationRepository;
@Mock FcmService fcmService;
@Mock LocationBroadcaster locationBroadcaster;
@InjectMocks NotificationService notificationService;
private User guardian;
private User user;
private PairingRelation activePairing;
@BeforeEach
void setUp() {
guardian = User.builder()
.id(1L).email("guardian@test.com").role("ROLE_GUARDIAN")
.displayName("Guardian").fcmToken("guardian-fcm").build();
user = User.builder()
.id(2L).email("user@test.com").role("ROLE_USER")
.displayName("User").fcmToken("user-fcm").build();
activePairing = PairingRelation.builder()
.id(10L).guardian(guardian).user(user).status(PairingStatus.ACTIVE).build();
}
// ===== SEND NOTIFICATION TESTS =====
@Test
@DisplayName("sendNotification - TEXT type: harus simpan dan kirim FCM ke user")
void sendNotification_textType_shouldSaveAndSendFcm() {
SendNotificationRequest req = new SendNotificationRequest();
req.setNotifType("TEXT");
req.setContent("Hati-hati di pertigaan!");
when(pairingRelationRepository.findByGuardian_IdAndStatus(1L, PairingStatus.ACTIVE))
.thenReturn(Optional.of(activePairing));
when(notifRepository.save(any(GuardianNotification.class))).thenAnswer(inv -> {
GuardianNotification n = inv.getArgument(0);
n.setId(100L);
return n;
});
NotificationResponse result = notificationService.sendNotification(1L, req);
assertThat(result).isNotNull();
assertThat(result.getContent()).isEqualTo("Hati-hati di pertigaan!");
verify(notifRepository).save(any(GuardianNotification.class));
verify(fcmService).sendToToken(eq("user-fcm"), anyString(), anyString(), anyMap());
}
@Test
@DisplayName("sendNotification - VOICE_NOTE type: harus simpan dengan tipe VOICE_NOTE")
void sendNotification_voiceNoteType_shouldSaveAsVoiceNote() {
SendNotificationRequest req = new SendNotificationRequest();
req.setNotifType("VOICE_NOTE");
req.setContent(null);
req.setVoiceNoteUrl("https://storage/voice/001.m4a");
req.setVoiceNoteDuration(12);
when(pairingRelationRepository.findByGuardian_IdAndStatus(1L, PairingStatus.ACTIVE))
.thenReturn(Optional.of(activePairing));
when(notifRepository.save(any(GuardianNotification.class))).thenAnswer(inv -> {
GuardianNotification n = inv.getArgument(0);
n.setId(101L);
n.setNotifType(NotificationType.VOICE_NOTE);
n.setVoiceNoteUrl("https://storage/voice/001.m4a");
return n;
});
NotificationResponse result = notificationService.sendNotification(1L, req);
assertThat(result.getVoiceNoteUrl()).isEqualTo("https://storage/voice/001.m4a");
verify(fcmService).sendToToken(eq("user-fcm"), anyString(), anyString(), anyMap());
}
@Test
@DisplayName("sendNotification - Guardian tidak punya active pairing harus throw PairingException")
void sendNotification_noPairing_shouldThrow() {
SendNotificationRequest req = new SendNotificationRequest();
req.setNotifType("TEXT");
req.setContent("test");
when(pairingRelationRepository.findByGuardian_IdAndStatus(1L, PairingStatus.ACTIVE))
.thenReturn(Optional.empty());
assertThatThrownBy(() -> notificationService.sendNotification(1L, req))
.isInstanceOf(PairingException.class)
.hasMessageContaining("Tidak ada user yang dipair");
verify(notifRepository, never()).save(any());
verify(fcmService, never()).sendToToken(any(), any(), any(), any());
}
// ===== MARK AS READ TESTS =====
@Test
@DisplayName("markAsRead - harus set isRead=true dan simpan")
void markAsRead_shouldSetReadTrue() {
GuardianNotification notif = GuardianNotification.builder()
.id(100L).userId(2L).guardianId(1L)
.notifType(NotificationType.TEXT).content("Test").isRead(false).build();
when(notifRepository.findByIdAndUserId(100L, 2L)).thenReturn(Optional.of(notif));
when(notifRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
notificationService.markAsRead(2L, 100L);
assertThat(notif.isRead()).isTrue();
verify(notifRepository).save(notif);
}
@Test
@DisplayName("markAsRead - notifikasi tidak ditemukan harus throw RuntimeException")
void markAsRead_notFound_shouldThrow() {
when(notifRepository.findByIdAndUserId(999L, 2L)).thenReturn(Optional.empty());
assertThatThrownBy(() -> notificationService.markAsRead(2L, 999L))
.isInstanceOf(RuntimeException.class);
}
// ===== UNREAD COUNT TESTS =====
@Test
@DisplayName("getUnreadCount - harus return jumlah notif yang belum dibaca")
void getUnreadCount_shouldReturnCorrectCount() {
when(notifRepository.countByUserIdAndIsReadFalse(2L)).thenReturn(5L);
long count = notificationService.getUnreadCount(2L);
assertThat(count).isEqualTo(5L);
}
@Test
@DisplayName("getUnreadCount - tidak ada notif belum dibaca harus return 0")
void getUnreadCount_noUnread_shouldReturnZero() {
when(notifRepository.countByUserIdAndIsReadFalse(2L)).thenReturn(0L);
long count = notificationService.getUnreadCount(2L);
assertThat(count).isZero();
}
// ===== GET NOTIFICATIONS TESTS =====
@Test
@DisplayName("getNotifications - harus return page notif untuk user")
void getNotifications_shouldReturnPagedResults() {
GuardianNotification notif = GuardianNotification.builder()
.id(1L).userId(2L).guardianId(1L)
.notifType(NotificationType.TEXT).content("Hello").isRead(false).build();
Page<GuardianNotification> page = new PageImpl<>(List.of(notif));
PageRequest pageable = PageRequest.of(0, 10);
when(notifRepository.findByUserIdOrderByCreatedAtDesc(2L, pageable)).thenReturn(page);
Page<NotificationResponse> result = notificationService.getNotifications(2L, pageable);
assertThat(result.getTotalElements()).isEqualTo(1);
assertThat(result.getContent().get(0).getContent()).isEqualTo("Hello");
}
}