1+ package com .swunitzel .fiterview .services ;
2+
3+ import com .swunitzel .fiterview .apiPayload .exception .handler .AnswerHandler ;
4+ import com .swunitzel .fiterview .apiPayload .exception .handler .CombineHandler ;
5+ import com .swunitzel .fiterview .apiPayload .exception .handler .InterviewHandler ;
6+ import com .swunitzel .fiterview .converter .ReportConverter ;
7+ import com .swunitzel .fiterview .domain .Answer ;
8+ import com .swunitzel .fiterview .domain .Combine ;
9+ import com .swunitzel .fiterview .domain .GazePoint ;
10+ import com .swunitzel .fiterview .domain .Interview ;
11+ import com .swunitzel .fiterview .dto .ReportDto ;
12+ import com .swunitzel .fiterview .repository .AnswerRepository ;
13+ import com .swunitzel .fiterview .repository .CombineRepository ;
14+ import com .swunitzel .fiterview .repository .InterviewRepository ;
15+ import org .junit .jupiter .api .DisplayName ;
16+ import org .junit .jupiter .api .Test ;
17+ import org .junit .jupiter .api .extension .ExtendWith ;
18+ import org .mockito .ArgumentCaptor ;
19+ import org .mockito .InjectMocks ;
20+ import org .mockito .Mock ;
21+ import org .mockito .MockedStatic ;
22+ import org .mockito .junit .jupiter .MockitoExtension ;
23+
24+ import java .time .LocalDateTime ;
25+ import java .util .Arrays ;
26+ import java .util .List ;
27+ import java .util .Optional ;
28+
29+ import static org .assertj .core .api .Assertions .assertThat ;
30+ import static org .assertj .core .api .Assertions .assertThatThrownBy ;
31+ import static org .mockito .ArgumentMatchers .anyFloat ;
32+ import static org .mockito .ArgumentMatchers .anyList ;
33+ import static org .mockito .Mockito .*;
34+
35+ @ ExtendWith (MockitoExtension .class )
36+ class ReportServiceTest {
37+
38+ @ Mock
39+ private AnswerRepository answerRepository ;
40+
41+ @ Mock
42+ private InterviewRepository interviewRepository ;
43+
44+ @ Mock
45+ private CombineRepository combineRepository ;
46+
47+ @ InjectMocks
48+ private ReportService reportService ;
49+
50+ @ Test
51+ @ DisplayName ("정상적인 비언어적 커뮤니케이션 리포트 생성 테스트" )
52+ void getNonverbalCommunicationReport_Success () {
53+ // Given
54+ String interviewId = "test-interview-id" ;
55+ String combineId = "test-combine-id" ;
56+
57+ // Mock Answer 데이터 생성
58+ Answer answer1 = createMockAnswer (5 , 3 , 2 , 0.8f , 10 , 15.0f );
59+ Answer answer2 = createMockAnswer (3 , 4 , 1 , 0.6f , 8 , 12.0f );
60+ List <Answer > answers = Arrays .asList (answer1 , answer2 );
61+
62+ // Mock Interview 데이터 생성
63+ Interview interview = createMockInterview (interviewId , combineId );
64+ Interview updatedInterview = createMockUpdatedInterview ();
65+
66+ // Mock Combine 데이터 생성
67+ Combine combine = createMockCombine (combineId );
68+
69+ // Mock ReportDto 생성
70+ ReportDto .NonverbalCommunicationReportDto expectedDto = createMockReportDto ();
71+
72+ // When
73+ when (answerRepository .findAllByInterviewId (interviewId )).thenReturn (answers );
74+ when (interviewRepository .findById (interviewId )).thenReturn (Optional .of (interview ));
75+ when (interview .updateNonverbalCommunicationReport (anyFloat (), anyFloat (), anyFloat (),
76+ anyFloat (), anyFloat (), anyFloat (), anyList ())).thenReturn (updatedInterview );
77+ when (combineRepository .findById (combineId )).thenReturn (Optional .of (combine ));
78+ try (MockedStatic <ReportConverter > mocked = mockStatic (ReportConverter .class )) {
79+ mocked .when (() -> ReportConverter .toNonverbalCommunicationReportDto (updatedInterview , combine ))
80+ .thenReturn (expectedDto );
81+
82+ // When
83+ ReportDto .NonverbalCommunicationReportDto result =
84+ reportService .getNonverbalCommunicationReport (interviewId );
85+
86+ // Then
87+ assertThat (result ).isNotNull ();
88+ assertThat (result ).isEqualTo (expectedDto );
89+ }
90+
91+ // Verify 메서드 호출 검증
92+ verify (answerRepository ).findAllByInterviewId (interviewId );
93+ verify (interviewRepository ).findById (interviewId );
94+ verify (combineRepository ).findById (combineId );
95+ verify (interview ).updateNonverbalCommunicationReport (anyFloat (), anyFloat (), anyFloat (),
96+ anyFloat (), anyFloat (), anyFloat (), anyList ());
97+ }
98+
99+ @ Test
100+ @ DisplayName ("Answer가 없을 경우 예외 발생 테스트" )
101+ void getNonverbalCommunicationReport_AnswerNotFound () {
102+ // Given
103+ String interviewId = "test-interview-id" ;
104+
105+ // When
106+ when (answerRepository .findAllByInterviewId (interviewId )).thenReturn (null );
107+
108+ // Then
109+ assertThatThrownBy (() -> reportService .getNonverbalCommunicationReport (interviewId ))
110+ .isInstanceOf (AnswerHandler .class );
111+
112+ verify (answerRepository ).findAllByInterviewId (interviewId );
113+ }
114+
115+ @ Test
116+ @ DisplayName ("Answer 필드가 null인 경우 예외 발생 테스트" )
117+ void getNonverbalCommunicationReport_AnswerFieldIsNull () {
118+ // Given
119+ String interviewId = "test-interview-id" ;
120+ Answer answerWithNullFields = createMockAnswerWithNullFields ();
121+ List <Answer > answers = Arrays .asList (answerWithNullFields );
122+
123+ // When
124+ when (answerRepository .findAllByInterviewId (interviewId )).thenReturn (answers );
125+
126+ // Then
127+ assertThatThrownBy (() -> reportService .getNonverbalCommunicationReport (interviewId ))
128+ .isInstanceOf (AnswerHandler .class );
129+
130+ verify (answerRepository ).findAllByInterviewId (interviewId );
131+ }
132+
133+ @ Test
134+ @ DisplayName ("Interview가 없을 경우 예외 발생 테스트" )
135+ void getNonverbalCommunicationReport_InterviewNotFound () {
136+ // Given
137+ String interviewId = "test-interview-id" ;
138+ Answer answer = createMockAnswer (5 , 3 , 2 , 0.8f , 10 , 15.0f );
139+ List <Answer > answers = Arrays .asList (answer );
140+
141+ // When
142+ when (answerRepository .findAllByInterviewId (interviewId )).thenReturn (answers );
143+ when (interviewRepository .findById (interviewId )).thenReturn (Optional .empty ());
144+
145+ // Then
146+ assertThatThrownBy (() -> reportService .getNonverbalCommunicationReport (interviewId ))
147+ .isInstanceOf (InterviewHandler .class );
148+
149+ verify (answerRepository ).findAllByInterviewId (interviewId );
150+ verify (interviewRepository ).findById (interviewId );
151+ }
152+
153+ @ Test
154+ @ DisplayName ("Combine이 없을 경우 예외 발생 테스트" )
155+ void getNonverbalCommunicationReport_CombineNotFound () {
156+ // Given
157+ String interviewId = "test-interview-id" ;
158+ String combineId = "test-combine-id" ;
159+ Answer answer = createMockAnswer (5 , 3 , 2 , 0.8f , 10 , 15.0f );
160+ List <Answer > answers = Arrays .asList (answer );
161+ Interview interview = createMockInterview (interviewId , combineId );
162+ Interview updatedInterview = createMockUpdatedInterview ();
163+
164+ // When
165+ when (answerRepository .findAllByInterviewId (interviewId )).thenReturn (answers );
166+ when (interviewRepository .findById (interviewId )).thenReturn (Optional .of (interview ));
167+ when (interview .updateNonverbalCommunicationReport (anyFloat (), anyFloat (), anyFloat (),
168+ anyFloat (), anyFloat (), anyFloat (), anyList ())).thenReturn (updatedInterview );
169+ when (combineRepository .findById (combineId )).thenReturn (Optional .empty ());
170+
171+ // Then
172+ assertThatThrownBy (() -> reportService .getNonverbalCommunicationReport (interviewId ))
173+ .isInstanceOf (CombineHandler .class );
174+
175+ verify (answerRepository ).findAllByInterviewId (interviewId );
176+ verify (interviewRepository ).findById (interviewId );
177+ verify (combineRepository ).findById (combineId );
178+ }
179+
180+ @ Test
181+ @ DisplayName ("GazePoints가 null인 경우 빈 리스트로 처리되는지 테스트" )
182+ void getNonverbalCommunicationReport_GazePointsNull () {
183+ // Given
184+ String interviewId = "test-interview-id" ;
185+ String combineId = "test-combine-id" ;
186+
187+ Answer answer = createMockAnswer (5 , 3 , 2 , 0.8f , 10 , 15.0f );
188+ when (answer .getGazePoints ()).thenReturn (null ); // GazePoints를 null로 설정
189+ List <Answer > answers = Arrays .asList (answer );
190+
191+ Interview interview = createMockInterview (interviewId , combineId );
192+ Interview updatedInterview = createMockUpdatedInterview ();
193+ Combine combine = createMockCombine (combineId );
194+ ReportDto .NonverbalCommunicationReportDto expectedDto = createMockReportDto ();
195+
196+ // When
197+ when (answerRepository .findAllByInterviewId (interviewId )).thenReturn (answers );
198+ when (interviewRepository .findById (interviewId )).thenReturn (Optional .of (interview ));
199+ when (interview .updateNonverbalCommunicationReport (anyFloat (), anyFloat (), anyFloat (),
200+ anyFloat (), anyFloat (), anyFloat (), anyList ())).thenReturn (updatedInterview );
201+ when (combineRepository .findById (combineId )).thenReturn (Optional .of (combine ));
202+ try (MockedStatic <ReportConverter > mocked = mockStatic (ReportConverter .class )) {
203+ mocked .when (() -> ReportConverter .toNonverbalCommunicationReportDto (updatedInterview , combine ))
204+ .thenReturn (expectedDto );
205+
206+ // When
207+ ReportDto .NonverbalCommunicationReportDto result =
208+ reportService .getNonverbalCommunicationReport (interviewId );
209+
210+ // Then
211+ assertThat (result ).isNotNull ();
212+ }
213+
214+ // gazePointsList에 빈 리스트가 포함되어야 함
215+ ArgumentCaptor <List <List <GazePoint >>> gazePointsCaptor =
216+ ArgumentCaptor .forClass (List .class );
217+ verify (interview ).updateNonverbalCommunicationReport (anyFloat (), anyFloat (), anyFloat (),
218+ anyFloat (), anyFloat (), anyFloat (), gazePointsCaptor .capture ());
219+
220+ List <List <GazePoint >> capturedGazePoints = gazePointsCaptor .getValue ();
221+ assertThat (capturedGazePoints ).hasSize (1 );
222+ assertThat (capturedGazePoints .get (0 )).isEmpty ();
223+ }
224+
225+ // Helper methods
226+ private Answer createMockAnswer (int shoulderTilt , int turnLeft , int turnRight ,
227+ float smileRatio , int gazeDown , float blinksPerMinute ) {
228+ Answer answer = mock (Answer .class );
229+ when (answer .getShoulderTiltCount ()).thenReturn (shoulderTilt );
230+ when (answer .getTurnLeftCount ()).thenReturn (turnLeft );
231+ when (answer .getTurnRightCount ()).thenReturn (turnRight );
232+ when (answer .getSmileRatio ()).thenReturn (smileRatio );
233+ when (answer .getGazeDownCount ()).thenReturn (gazeDown );
234+ when (answer .getBlinksPerMinute ()).thenReturn (blinksPerMinute );
235+ when (answer .getGazePoints ()).thenReturn (Arrays .asList (
236+ createRealGazePoint (5 , 3 ),
237+ createRealGazePoint (7 , 4 )
238+ ));
239+ return answer ;
240+ }
241+
242+ private Answer createMockAnswerWithNullFields () {
243+ Answer answer = mock (Answer .class );
244+ when (answer .getShoulderTiltCount ()).thenReturn (null ); // null 필드
245+ return answer ;
246+ }
247+
248+ private GazePoint createRealGazePoint (int x , int y ) {
249+ return new GazePoint (x , y , LocalDateTime .now ());
250+ }
251+
252+ private Interview createMockInterview (String interviewId , String combineId ) {
253+ Interview interview = mock (Interview .class );
254+ when (interview .getCombineId ()).thenReturn (combineId );
255+ return interview ;
256+ }
257+
258+ private Interview createMockUpdatedInterview () {
259+ return mock (Interview .class );
260+ }
261+
262+ private Combine createMockCombine (String combineId ) {
263+ Combine combine = mock (Combine .class );
264+ return combine ;
265+ }
266+
267+ private ReportDto .NonverbalCommunicationReportDto createMockReportDto () {
268+ return mock (ReportDto .NonverbalCommunicationReportDto .class );
269+ }
270+ }
0 commit comments