33import static org .junit .jupiter .api .Assertions .*;
44import static org .mockito .BDDMockito .*;
55
6+ import java .util .List ;
67import java .util .Optional ;
78
89import org .junit .jupiter .api .DisplayName ;
910import org .junit .jupiter .api .Test ;
1011import org .junit .jupiter .api .extension .ExtendWith ;
12+ import org .mockito .ArgumentMatchers ;
1113import org .mockito .InjectMocks ;
1214import org .mockito .Mock ;
1315import org .mockito .junit .jupiter .MockitoExtension ;
16+ import org .springframework .data .domain .PageRequest ;
17+ import org .springframework .data .domain .Slice ;
18+ import org .springframework .data .domain .SliceImpl ;
1419
20+ import com .example .log4u .common .dto .PageResponse ;
21+ import com .example .log4u .domain .follow .repository .FollowRepository ;
1522import com .example .log4u .domain .user .dto .NicknameValidationResponseDto ;
1623import com .example .log4u .domain .user .dto .UserProfileMakeRequestDto ;
24+ import com .example .log4u .domain .user .dto .UserProfileResponseDto ;
1725import com .example .log4u .domain .user .dto .UserProfileUpdateRequestDto ;
1826import com .example .log4u .domain .user .entity .User ;
1927import com .example .log4u .domain .user .exception .UserNotFoundException ;
@@ -29,7 +37,10 @@ class UserServiceTest {
2937
3038 @ Mock
3139 private UserRepository userRepository ;
32-
40+
41+ @ Mock
42+ private FollowRepository followRepository ;
43+
3344 @ Test
3445 @ DisplayName ("내 프로필을 생성하고 저장해야 한다." )
3546 void shouldCreateAndSaveMyUserProfile () {
@@ -116,4 +127,103 @@ void shouldThrowExceptionWhenUserNotFound() {
116127 verify (userRepository ).findById (userId );
117128 }
118129
130+ @ Test
131+ @ DisplayName ("닉네임으로 유저를 검색하고 팔로워 수 높은 순으로 정렬해야 한다" )
132+ void shouldSearchUsersByNicknameAndSortByFollowerCount () {
133+ // given
134+ String nickname = "test" ;
135+ Long cursorId = null ;
136+ int size = 10 ;
137+
138+ // 테스트용 유저 목록 생성
139+ User user1 = UserFixture .createUserWithId (1L , "User1" , "test1" );
140+ User user2 = UserFixture .createUserWithId (2L , "User2" , "test2" );
141+ User user3 = UserFixture .createUserWithId (3L , "User3" , "test3" );
142+
143+ List <User > users = List .of (user1 , user2 , user3 );
144+ Slice <User > userSlice = new SliceImpl <>(users , PageRequest .of (0 , size ), false );
145+
146+ // Mock 설정
147+ when (userRepository .searchUsersByCursor (
148+ eq (nickname ),
149+ eq (Long .MAX_VALUE ),
150+ ArgumentMatchers .any (PageRequest .class )))
151+ .thenReturn (userSlice );
152+
153+ // 각 유저의 팔로워/팔로잉 수 설정
154+ when (followRepository .countByTargetId (1L )).thenReturn (10L );
155+ when (followRepository .countByInitiatorId (1L )).thenReturn (5L );
156+
157+ when (followRepository .countByTargetId (2L )).thenReturn (20L );
158+ when (followRepository .countByInitiatorId (2L )).thenReturn (15L );
159+
160+ when (followRepository .countByTargetId (3L )).thenReturn (30L );
161+ when (followRepository .countByInitiatorId (3L )).thenReturn (25L );
162+
163+ // when
164+ PageResponse <UserProfileResponseDto > result = userService .searchUsersByCursor (nickname , cursorId , size );
165+
166+ // then
167+ assertNotNull (result );
168+ assertEquals (3 , result .list ().size ());
169+
170+ // 팔로워 수 확인
171+ assertEquals (10L , result .list ().get (0 ).followers ());
172+ assertEquals (20L , result .list ().get (1 ).followers ());
173+ assertEquals (30L , result .list ().get (2 ).followers ());
174+
175+ // 팔로잉 수 확인
176+ assertEquals (5L , result .list ().get (0 ).followings ());
177+ assertEquals (15L , result .list ().get (1 ).followings ());
178+ assertEquals (25L , result .list ().get (2 ).followings ());
179+
180+ // 다음 커서 확인
181+ assertEquals (3L , result .pageInfo ().nextCursor ());
182+
183+ // 메서드 호출 확인
184+ verify (userRepository ).searchUsersByCursor (
185+ eq (nickname ),
186+ eq (Long .MAX_VALUE ),
187+ ArgumentMatchers .any (PageRequest .class ));
188+
189+ verify (followRepository , times (3 )).countByTargetId (anyLong ());
190+ verify (followRepository , times (3 )).countByInitiatorId (anyLong ());
191+ }
192+
193+ @ Test
194+ @ DisplayName ("검색 결과가 없으면 빈 리스트를 반환해야 한다" )
195+ void shouldReturnEmptyListWhenNoSearchResults () {
196+ // given
197+ String nickname = "nonexistent" ;
198+ Long cursorId = null ;
199+ int size = 10 ;
200+
201+ List <User > emptyList = List .of ();
202+ Slice <User > emptySlice = new SliceImpl <>(emptyList , PageRequest .of (0 , size ), false );
203+
204+ // Mock 설정
205+ when (userRepository .searchUsersByCursor (
206+ eq (nickname ),
207+ eq (Long .MAX_VALUE ),
208+ ArgumentMatchers .any (PageRequest .class )))
209+ .thenReturn (emptySlice );
210+
211+ // when
212+ PageResponse <UserProfileResponseDto > result = userService .searchUsersByCursor (nickname , cursorId , size );
213+
214+ // then
215+ assertNotNull (result );
216+ assertTrue (result .list ().isEmpty ());
217+ assertNull (result .pageInfo ().nextCursor ());
218+
219+ // 메서드 호출 확인
220+ verify (userRepository ).searchUsersByCursor (
221+ eq (nickname ),
222+ eq (Long .MAX_VALUE ),
223+ ArgumentMatchers .any (PageRequest .class ));
224+
225+ // 팔로워/팔로잉 수 조회 메서드가 호출되지 않아야 함
226+ verify (followRepository , never ()).countByTargetId (anyLong ());
227+ verify (followRepository , never ()).countByInitiatorId (anyLong ());
228+ }
119229}
0 commit comments