1+ package com .back .domain .notification .event .community ;
2+
3+ import com .back .domain .notification .service .NotificationService ;
4+ import com .back .domain .user .entity .User ;
5+ import com .back .domain .user .repository .UserRepository ;
6+ import org .junit .jupiter .api .BeforeEach ;
7+ import org .junit .jupiter .api .DisplayName ;
8+ import org .junit .jupiter .api .Test ;
9+ import org .junit .jupiter .api .extension .ExtendWith ;
10+ import org .mockito .InjectMocks ;
11+ import org .mockito .Mock ;
12+ import org .mockito .junit .jupiter .MockitoExtension ;
13+
14+ import java .util .Optional ;
15+
16+ import static org .assertj .core .api .Assertions .*;
17+ import static org .mockito .ArgumentMatchers .*;
18+ import static org .mockito .BDDMockito .*;
19+
20+ @ ExtendWith (MockitoExtension .class )
21+ @ DisplayName ("CommunityNotificationEventListener 테스트" )
22+ class CommunityNotificationEventListenerTest {
23+
24+ @ Mock
25+ private NotificationService notificationService ;
26+
27+ @ Mock
28+ private UserRepository userRepository ;
29+
30+ @ InjectMocks
31+ private CommunityNotificationEventListener listener ;
32+
33+ private User actor ;
34+ private User receiver ;
35+
36+ @ BeforeEach
37+ void setUp () {
38+ actor = User .builder ()
39+ .id (1L )
40+ .username ("actor" )
41+ 42+ .build ();
43+
44+ receiver = User .builder ()
45+ .id (2L )
46+ .username ("receiver" )
47+ 48+ .build ();
49+ }
50+
51+ // ====================== 댓글 작성 이벤트 ======================
52+
53+ @ Test
54+ @ DisplayName ("댓글 작성 이벤트 수신 - 알림 생성 성공" )
55+ void t1 () {
56+ // given
57+ CommentCreatedEvent event = new CommentCreatedEvent (
58+ 1L , // actorId (댓글 작성자)
59+ 2L , // receiverId (게시글 작성자)
60+ 100L , // postId
61+ 200L , // commentId
62+ "댓글 내용"
63+ );
64+
65+ given (userRepository .findById (1L )).willReturn (Optional .of (actor ));
66+ given (userRepository .findById (2L )).willReturn (Optional .of (receiver ));
67+
68+ // when
69+ listener .handleCommentCreated (event );
70+
71+ // then
72+ verify (notificationService ).createCommunityNotification (
73+ eq (receiver ),
74+ eq (actor ),
75+ anyString (), // title
76+ anyString (), // content
77+ eq ("/posts/100" )
78+ );
79+ }
80+
81+ @ Test
82+ @ DisplayName ("댓글 작성 이벤트 - 작성자(actor) 없음" )
83+ void t2 () {
84+ // given
85+ CommentCreatedEvent event = new CommentCreatedEvent (
86+ 999L , // 존재하지 않는 actorId
87+ 2L ,
88+ 100L ,
89+ 200L ,
90+ "댓글 내용"
91+ );
92+
93+ given (userRepository .findById (999L )).willReturn (Optional .empty ());
94+
95+ // when
96+ listener .handleCommentCreated (event );
97+
98+ // then
99+ verify (notificationService , never ()).createCommunityNotification (
100+ any (), any (), anyString (), anyString (), anyString ()
101+ );
102+ }
103+
104+ @ Test
105+ @ DisplayName ("댓글 작성 이벤트 - 수신자(receiver) 없음" )
106+ void t3 () {
107+ // given
108+ CommentCreatedEvent event = new CommentCreatedEvent (
109+ 1L ,
110+ 999L , // 존재하지 않는 receiverId
111+ 100L ,
112+ 200L ,
113+ "댓글 내용"
114+ );
115+
116+ given (userRepository .findById (1L )).willReturn (Optional .of (actor ));
117+ given (userRepository .findById (999L )).willReturn (Optional .empty ());
118+
119+ // when
120+ listener .handleCommentCreated (event );
121+
122+ // then
123+ verify (notificationService , never ()).createCommunityNotification (
124+ any (), any (), anyString (), anyString (), anyString ()
125+ );
126+ }
127+
128+ // ====================== 대댓글 작성 이벤트 ======================
129+
130+ @ Test
131+ @ DisplayName ("대댓글 작성 이벤트 수신 - 알림 생성 성공" )
132+ void t4 () {
133+ // given
134+ ReplyCreatedEvent event = new ReplyCreatedEvent (
135+ 1L , // actorId (대댓글 작성자)
136+ 2L , // receiverId (댓글 작성자)
137+ 100L , // postId
138+ 200L , // parentCommentId
139+ 300L , // replyId
140+ "대댓글 내용"
141+ );
142+
143+ given (userRepository .findById (1L )).willReturn (Optional .of (actor ));
144+ given (userRepository .findById (2L )).willReturn (Optional .of (receiver ));
145+
146+ // when
147+ listener .handleReplyCreated (event );
148+
149+ // then
150+ verify (notificationService ).createCommunityNotification (
151+ eq (receiver ),
152+ eq (actor ),
153+ anyString (),
154+ anyString (),
155+ eq ("/posts/100#comment-200" )
156+ );
157+ }
158+
159+ @ Test
160+ @ DisplayName ("대댓글 작성 이벤트 - 작성자(actor) 없음" )
161+ void t5 () {
162+ // given
163+ ReplyCreatedEvent event = new ReplyCreatedEvent (
164+ 999L , // 존재하지 않는 actorId
165+ 2L ,
166+ 100L ,
167+ 200L ,
168+ 300L ,
169+ "대댓글 내용"
170+ );
171+
172+ given (userRepository .findById (999L )).willReturn (Optional .empty ());
173+
174+ // when
175+ listener .handleReplyCreated (event );
176+
177+ // then
178+ verify (notificationService , never ()).createCommunityNotification (
179+ any (), any (), anyString (), anyString (), anyString ()
180+ );
181+ }
182+
183+ // ====================== 게시글 좋아요 이벤트 ======================
184+
185+ @ Test
186+ @ DisplayName ("게시글 좋아요 이벤트 수신 - 알림 생성 성공" )
187+ void t6 () {
188+ // given
189+ PostLikedEvent event = new PostLikedEvent (
190+ 1L , // actorId (좋아요 누른 사람)
191+ 2L , // receiverId (게시글 작성자)
192+ 100L , // postId
193+ "게시글 제목"
194+ );
195+
196+ given (userRepository .findById (1L )).willReturn (Optional .of (actor ));
197+ given (userRepository .findById (2L )).willReturn (Optional .of (receiver ));
198+
199+ // when
200+ listener .handlePostLiked (event );
201+
202+ // then
203+ verify (notificationService ).createCommunityNotification (
204+ eq (receiver ),
205+ eq (actor ),
206+ anyString (),
207+ anyString (),
208+ eq ("/posts/100" )
209+ );
210+ }
211+
212+ @ Test
213+ @ DisplayName ("게시글 좋아요 이벤트 - 수신자 없음" )
214+ void t7 () {
215+ // given
216+ PostLikedEvent event = new PostLikedEvent (
217+ 1L ,
218+ 999L , // 존재하지 않는 receiverId
219+ 100L ,
220+ "게시글 제목"
221+ );
222+
223+ given (userRepository .findById (1L )).willReturn (Optional .of (actor ));
224+ given (userRepository .findById (999L )).willReturn (Optional .empty ());
225+
226+ // when
227+ listener .handlePostLiked (event );
228+
229+ // then
230+ verify (notificationService , never ()).createCommunityNotification (
231+ any (), any (), anyString (), anyString (), anyString ()
232+ );
233+ }
234+
235+ // ====================== 댓글 좋아요 이벤트 ======================
236+
237+ @ Test
238+ @ DisplayName ("댓글 좋아요 이벤트 수신 - 알림 생성 성공" )
239+ void t8 () {
240+ // given
241+ CommentLikedEvent event = new CommentLikedEvent (
242+ 1L , // actorId
243+ 2L , // receiverId
244+ 100L , // postId
245+ 200L , // commentId,
246+ "댓글 내용"
247+ );
248+
249+ given (userRepository .findById (1L )).willReturn (Optional .of (actor ));
250+ given (userRepository .findById (2L )).willReturn (Optional .of (receiver ));
251+
252+ // when
253+ listener .handleCommentLiked (event );
254+
255+ // then
256+ verify (notificationService ).createCommunityNotification (
257+ eq (receiver ),
258+ eq (actor ),
259+ anyString (),
260+ anyString (),
261+ eq ("/posts/100#comment-200" )
262+ );
263+ }
264+
265+ @ Test
266+ @ DisplayName ("댓글 좋아요 이벤트 - 작성자와 수신자가 같은 경우" )
267+ void t9 () {
268+ // given
269+ CommentLikedEvent event = new CommentLikedEvent (
270+ 1L , // actorId
271+ 1L , // receiverId (같은 사람)
272+ 100L ,
273+ 200L ,
274+ "댓글 내용"
275+ );
276+
277+ given (userRepository .findById (1L )).willReturn (Optional .of (actor ));
278+
279+ // when
280+ listener .handleCommentLiked (event );
281+
282+ // then
283+ // NotificationService에서 자기 자신 알림 필터링 처리
284+ verify (notificationService ).createCommunityNotification (
285+ eq (actor ), // receiver
286+ eq (actor ), // actor
287+ anyString (),
288+ anyString (),
289+ anyString ()
290+ );
291+ }
292+
293+ // ====================== 예외 처리 테스트 ======================
294+
295+ @ Test
296+ @ DisplayName ("알림 생성 중 예외 발생 - 로그만 출력하고 예외 전파 안함" )
297+ void t10 () {
298+ // given
299+ CommentCreatedEvent event = new CommentCreatedEvent (
300+ 1L , 2L , 100L , 200L , "댓글 내용"
301+ );
302+
303+ given (userRepository .findById (1L )).willReturn (Optional .of (actor ));
304+ given (userRepository .findById (2L )).willReturn (Optional .of (receiver ));
305+
306+ willThrow (new RuntimeException ("알림 생성 실패" ))
307+ .given (notificationService ).createCommunityNotification (
308+ any (), any (), anyString (), anyString (), anyString ()
309+ );
310+
311+ // when & then - 예외가 전파되지 않아야 함
312+ assertThatCode (() -> listener .handleCommentCreated (event ))
313+ .doesNotThrowAnyException ();
314+
315+ verify (notificationService ).createCommunityNotification (
316+ any (), any (), anyString (), anyString (), anyString ()
317+ );
318+ }
319+ }
0 commit comments