package com.mydreamjob.notification; import com.mydreamjob.common.exception.BusinessException; import com.mydreamjob.common.exception.ErrorCode; import com.mydreamjob.auth.UserRepository; import com.mydreamjob.company.CompanyRepository; import org.junit.jupiter.api.BeforeEach; 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.PageImpl; import org.springframework.data.domain.PageRequest; import java.util.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) class NotificationServiceTest { @Mock private NotificationRepository notificationRepository; @Mock private PushProvider pushProvider; @Mock private UserRepository userRepository; @Mock private CompanyRepository companyRepository; @InjectMocks private NotificationService notificationService; private static final Long USER_A = 100L; private static final Long USER_B = 200L; private static final Long NOTIF_ID = 1L; private Notification notif; @BeforeEach void setUp() { notif = Notification.builder().id(NOTIF_ID).userId(USER_A) .type("APPLICATION").title("新投递").content("有新的投递").read(false).build(); } @Test void create_shouldSaveAndPush() { when(notificationRepository.save(any())).thenAnswer(inv -> inv.getArgument(0)); when(pushProvider.send(eq(USER_A), any(), any())).thenReturn(true); Notification n = notificationService.create(USER_A, "APPLICATION", "新投递", "内容"); assertEquals("新投递", n.getTitle()); verify(pushProvider, times(1)).send(eq(USER_A), any(), any()); } @Test void list_shouldReturnPaged() { when(notificationRepository.findByUserIdOrderByCreatedAtDesc(eq(USER_A), any())) .thenReturn(new PageImpl<>(List.of(notif))); var r = notificationService.list(USER_A, 0, 20); assertEquals(1, r.getTotalElements()); } @Test void list_invalidSize_shouldReturn400() { assertThrows(BusinessException.class, () -> notificationService.list(USER_A, 0, 0)); assertThrows(BusinessException.class, () -> notificationService.list(USER_A, -1, 20)); assertThrows(BusinessException.class, () -> notificationService.list(USER_A, 0, 51)); } @Test void markRead_shouldSucceed() { when(notificationRepository.findById(NOTIF_ID)).thenReturn(Optional.of(notif)); when(notificationRepository.save(any())).thenAnswer(inv -> inv.getArgument(0)); notificationService.markRead(USER_A, NOTIF_ID); assertTrue(notif.getRead()); } @Test void markRead_alreadyRead_shouldBeIdempotent() { notif.setRead(true); when(notificationRepository.findById(NOTIF_ID)).thenReturn(Optional.of(notif)); notificationService.markRead(USER_A, NOTIF_ID); verify(notificationRepository, never()).save(any()); } @Test void markRead_otherUser_shouldReturn403() { when(notificationRepository.findById(NOTIF_ID)).thenReturn(Optional.of(notif)); assertThrows(BusinessException.class, () -> notificationService.markRead(USER_B, NOTIF_ID)); } @Test void markRead_notFound_shouldReturn404() { when(notificationRepository.findById(999L)).thenReturn(Optional.empty()); BusinessException ex = assertThrows(BusinessException.class, () -> notificationService.markRead(USER_A, 999L)); assertEquals(ErrorCode.NOTIFICATION_NOT_FOUND.getCode(), ex.getErrorCodeInt()); } @Test void unreadCount_shouldReturnCount() { when(notificationRepository.countUnreadByUserId(USER_A)).thenReturn(5L); assertEquals(5L, notificationService.unreadCount(USER_A)); } @Test void markAllRead_shouldMarkUnread() { notif.setRead(false); when(notificationRepository.findByUserIdOrderByCreatedAtDesc(eq(USER_A), any())) .thenReturn(new PageImpl<>(List.of(notif))); when(notificationRepository.save(any())).thenAnswer(inv -> inv.getArgument(0)); int marked = notificationService.markAllRead(USER_A); assertEquals(1, marked); assertTrue(notif.getRead()); } }