44import static org .mockito .ArgumentMatchers .*;
55import static org .mockito .BDDMockito .*;
66
7+ import BE_Elixir .Elixir .domain .achievement .entity .Achievement ;
8+ import BE_Elixir .Elixir .domain .achievement .entity .MemberAchievement ;
9+ import BE_Elixir .Elixir .domain .achievement .repository .AchievementRepository ;
10+ import BE_Elixir .Elixir .domain .achievement .repository .MemberAchievementRepository ;
11+ import BE_Elixir .Elixir .domain .challenge .entity .Challenge ;
12+ import BE_Elixir .Elixir .domain .challenge .entity .ChallengeAchievement ;
13+ import BE_Elixir .Elixir .domain .challenge .repository .ChallengeAchievementRepository ;
14+ import BE_Elixir .Elixir .domain .challenge .repository .ChallengeRepository ;
715import BE_Elixir .Elixir .domain .member .dto .request .MemberProfileRequestDTO ;
816import BE_Elixir .Elixir .domain .member .dto .request .SurveyRequestDTO ;
917import BE_Elixir .Elixir .domain .member .dto .response .MemberResponseDTO ;
1018import BE_Elixir .Elixir .domain .member .dto .response .SurveyResponseDTO ;
1119import BE_Elixir .Elixir .domain .member .entity .Member ;
1220import BE_Elixir .Elixir .domain .member .repository .MemberRepository ;
21+ import BE_Elixir .Elixir .domain .recipe .entity .Recipe ;
22+ import BE_Elixir .Elixir .domain .recipe .entity .RecipeEvent ;
23+ import BE_Elixir .Elixir .domain .recipe .repository .RecipeEventRepository ;
24+ import BE_Elixir .Elixir .domain .recipe .repository .RecipeRepository ;
1325import BE_Elixir .Elixir .global .enums .LoginType ;
1426import BE_Elixir .Elixir .global .exception .CustomException ;
1527import BE_Elixir .Elixir .global .exception .ErrorCode ;
2436import org .mockito .junit .jupiter .MockitoExtension ;
2537import org .springframework .web .multipart .MultipartFile ;
2638
39+ import static org .assertj .core .api .Assertions .assertThat ;
40+ import static org .assertj .core .api .Assertions .assertThatThrownBy ;
41+
2742import java .io .IOException ;
43+ import java .time .LocalDateTime ;
2844import java .util .*;
45+ import java .util .stream .IntStream ;
2946
3047@ ExtendWith (MockitoExtension .class )
3148class MyPageServiceTest {
@@ -34,14 +51,25 @@ class MyPageServiceTest {
3451 private MyPageService myPageService ;
3552
3653 @ Mock private MemberRepository memberRepository ;
54+ @ Mock private RecipeRepository recipeRepository ;
55+ @ Mock private RecipeEventRepository recipeEventRepository ;
56+ @ Mock private ChallengeRepository challengeRepository ;
57+ @ Mock private ChallengeAchievementRepository challengeAchievementRepository ;
58+ @ Mock private AchievementRepository achievementRepository ;
59+ @ Mock private MemberAchievementRepository memberAchievementRepository ;
3760 @ Mock private S3Service s3Service ;
3861 @ Mock private MultipartFile multipartFile ;
3962
4063 private Member member ;
64+ private Challenge challenge ;
65+ private ChallengeAchievement challengeAchievement ;
66+ private Achievement achievement ;
67+ private MemberAchievement memberAchievement ;
4168
4269 @ BeforeEach
4370 void setUp () {
4471 member = Member .builder ()
72+ .id (1L )
4573 .email ("test@example.com" )
4674 .password ("encoded-password" )
4775 .nickname ("test" )
@@ -59,6 +87,35 @@ void setUp() {
5987 .reason_항산화강화 (true )
6088 .reason_혈당조절 (true )
6189 .build ();
90+
91+ // 기본 Challenge 데이터
92+ challenge = new Challenge ();
93+ challenge .setId (100L );
94+ challenge .setYear (2025 );
95+ challenge .setMonth (8 );
96+ challenge .setAchievementName ("8월 챌린지" );
97+ challenge .setAchievementImageUrl ("color.jpg" );
98+ challenge .setGrayAchievementImageUrl ("gray.jpg" );
99+
100+ // 기본 ChallengeAchievement (미달성)
101+ challengeAchievement = new ChallengeAchievement ();
102+ challengeAchievement .setChallengeId (challenge .getId ());
103+ challengeAchievement .setMemberId (member .getId ());
104+ challengeAchievement .setStep4Goal1Achieved (false );
105+ challengeAchievement .setStep4Goal2Achieved (false );
106+
107+ // 일반 업적
108+ achievement = new Achievement ();
109+ achievement .setId (200L );
110+ achievement .setAchievementName ("첫 업적" );
111+ achievement .setAchievementImageUrl ("achieve.jpg" );
112+
113+ // 일반 업적 달성 정보 (기본: 미달성 상태)
114+ memberAchievement = new MemberAchievement ();
115+ memberAchievement .setAchievement (achievement );
116+ memberAchievement .setMember (member );
117+ memberAchievement .setCurrentProgress (0 );
118+ memberAchievement .setCompleted (false );
62119 }
63120
64121 @ Nested
@@ -309,7 +366,7 @@ void updateSurvey_Success_IndividualFields() {
309366 }
310367
311368 @ Test
312- @ DisplayName ("실패 : 회원이 존재하지 않음" )
369+ @ DisplayName ("예외 : 회원이 존재하지 않음" )
313370 void updateSurvey_Fail_MemberNotFound () {
314371 // given
315372 Long memberId = 999L ;
@@ -327,4 +384,264 @@ void updateSurvey_Fail_MemberNotFound() {
327384 verify (memberRepository , never ()).save (any ());
328385 }
329386 }
387+
388+ @ Nested
389+ @ DisplayName ("내가 작성한 레시피 조회 테스트" )
390+ class GetMyRecipes {
391+
392+ @ Test
393+ @ DisplayName ("성공: 로그인한 사용자의 모든 레시피 조회" )
394+ void success () {
395+ // given
396+ Recipe recipe = new Recipe ();
397+ recipe .setId (1L );
398+ recipe .setImageUrl ("image.jpg" );
399+
400+ given (memberRepository .findById (1L )).willReturn (Optional .of (member ));
401+ given (recipeRepository .findAllByMember (member )).willReturn (List .of (recipe ));
402+
403+ // when
404+ var result = myPageService .getMyRecipes (1L );
405+
406+ // then
407+ assertThat (result ).hasSize (1 );
408+ assertThat (result .get (0 ).getImageUrl ()).isEqualTo ("image.jpg" );
409+ }
410+
411+ @ Test
412+ @ DisplayName ("예외: 회원을 찾을 수 없음" )
413+ void fail_memberNotFound () {
414+ // given
415+ given (memberRepository .findById (1L )).willReturn (Optional .empty ());
416+
417+ // when & then
418+ assertThatThrownBy (() -> myPageService .getMyRecipes (1L ))
419+ .isInstanceOf (CustomException .class )
420+ .extracting (e -> ((CustomException ) e ).getErrorCode ())
421+ .isEqualTo (ErrorCode .MEMBER_NOT_FOUND );
422+ }
423+ }
424+
425+ @ Nested
426+ @ DisplayName ("나의 레시피 스크랩 테스트" )
427+ class GetMyScrapRecipes {
428+
429+ @ Test
430+ @ DisplayName ("성공: 스크랩한 레시피 목록 반환" )
431+ void success () {
432+ // given
433+ Recipe recipe = new Recipe ();
434+ recipe .setId (1L );
435+ recipe .setImageUrl ("scrap.jpg" );
436+
437+ RecipeEvent event = new RecipeEvent ();
438+ event .setRecipe (recipe );
439+
440+ given (memberRepository .findById (1L )).willReturn (Optional .of (member ));
441+ given (recipeEventRepository .findByMemberAndScrapFlagTrue (member ))
442+ .willReturn (List .of (event ));
443+
444+ // when
445+ var result = myPageService .getMyScrapRecipes (1L );
446+
447+ // then
448+ assertThat (result ).hasSize (1 );
449+ assertThat (result .get (0 ).getImageUrl ()).isEqualTo ("scrap.jpg" );
450+ }
451+
452+ @ Test
453+ @ DisplayName ("예외: 회원 없음" )
454+ void fail_memberNotFound () {
455+ // given
456+ given (memberRepository .findById (1L )).willReturn (Optional .empty ());
457+
458+ // when & then
459+ assertThatThrownBy (() -> myPageService .getMyScrapRecipes (1L ))
460+ .isInstanceOf (CustomException .class )
461+ .extracting (e -> ((CustomException ) e ).getErrorCode ())
462+ .isEqualTo (ErrorCode .MEMBER_NOT_FOUND );
463+ }
464+ }
465+
466+ @ Nested
467+ @ DisplayName ("다른 사용자가 작성한 레시피 조회 테스트" )
468+ class GetUserRecipes {
469+
470+ @ Test
471+ @ DisplayName ("성공: 다른 사용자의 레시피 최대 9개 반환" )
472+ void success () {
473+ // given
474+ List <Recipe > recipes = IntStream .range (0 , 12 )
475+ .mapToObj (i -> {
476+ Recipe r = new Recipe ();
477+ r .setId ((long ) i );
478+ r .setImageUrl ("img" + i );
479+ return r ;
480+ })
481+ .toList ();
482+
483+ given (memberRepository .findById (1L )).willReturn (Optional .of (member ));
484+ given (recipeRepository .findAllByMember (member )).willReturn (recipes );
485+
486+ // when
487+ var result = myPageService .getUserRecipes (1L );
488+
489+ // then
490+ assertThat (result ).hasSize (9 );
491+ }
492+
493+ @ Test
494+ @ DisplayName ("예외: 회원 없음" )
495+ void fail_memberNotFound () {
496+ // given
497+ given (memberRepository .findById (1L )).willReturn (Optional .empty ());
498+
499+ // when & then
500+ assertThatThrownBy (() -> myPageService .getUserRecipes (1L ))
501+ .isInstanceOf (CustomException .class )
502+ .extracting (e -> ((CustomException ) e ).getErrorCode ())
503+ .isEqualTo (ErrorCode .MEMBER_NOT_FOUND );
504+ }
505+ }
506+
507+ @ Nested
508+ @ DisplayName ("챌린지 업적 조회 테스트" )
509+ class ChallengeAchievementTests {
510+
511+ @ Test
512+ @ DisplayName ("성공: 모든 챌린지 업적 조회" )
513+ void getAllChallengeAchievements_success () {
514+ // given
515+ Long memberId = 1L ;
516+ // 달성 상태로 변경
517+ challengeAchievement .setStep4Goal1Achieved (true );
518+ challengeAchievement .setStep4Goal2Achieved (true );
519+
520+ given (memberRepository .findById (memberId )).willReturn (Optional .of (member ));
521+ given (challengeRepository .findAllOrderedByYearAndMonth ()).willReturn (List .of (challenge ));
522+ given (challengeAchievementRepository .findByMemberId (1L ))
523+ .willReturn (List .of (challengeAchievement ));
524+
525+ // when
526+ var result = myPageService .getAllChallengeAchievements (1L );
527+
528+ // then
529+ assertThat (result ).hasSize (1 );
530+ assertThat (result .get (0 ).isChallengeCompleted ()).isTrue ();
531+ assertThat (result .get (0 ).getAchievementImageUrl ()).isEqualTo ("color.jpg" );
532+ }
533+
534+ @ Test
535+ @ DisplayName ("성공: 최신 3개 챌린지 업적 조회" )
536+ void getTop3ChallengeAchievements_success () {
537+ // given
538+ Long memberId = 1L ;
539+ challengeAchievement .setStep4Goal1Achieved (true );
540+ challengeAchievement .setStep4Goal2Achieved (true );
541+
542+ given (memberRepository .findById (memberId )).willReturn (Optional .of (member ));
543+ given (challengeAchievementRepository .findByMemberId (1L ))
544+ .willReturn (List .of (challengeAchievement ));
545+ given (challengeRepository .findAllById (anySet ()))
546+ .willReturn (List .of (challenge ));
547+
548+ // when
549+ var result = myPageService .getTop3ChallengeAchievements (1L );
550+
551+
552+ // then
553+ assertThat (result ).hasSize (1 );
554+ assertThat (result .get (0 ).getAchievementName ()).isEqualTo ("8월 챌린지" );
555+ assertThat (result .get (0 ).getAchievementImageUrl ()).isEqualTo ("color.jpg" );
556+ }
557+
558+ @ Test
559+ @ DisplayName ("예외: 회원 없음" )
560+ void fail_memberNotFound () {
561+ // given
562+ given (memberRepository .findById (1L )).willReturn (Optional .empty ());
563+
564+
565+ // when & then
566+ assertThatThrownBy (() -> myPageService .getAllChallengeAchievements (1L ))
567+ .isInstanceOf (CustomException .class )
568+ .extracting (e -> ((CustomException ) e ).getErrorCode ())
569+ .isEqualTo (ErrorCode .MEMBER_NOT_FOUND );
570+ }
571+ }
572+
573+ @ Nested
574+ @ DisplayName ("일반 업적 조회 테스트" )
575+ class StatsAchievementTests {
576+
577+ @ Test
578+ @ DisplayName ("성공: 모든 일반 업적 조회" )
579+ void getAllMyStatsAchievements_success () {
580+ // given
581+ given (memberRepository .findById (1L )).willReturn (Optional .of (member ));
582+ given (achievementRepository .findAll ()).willReturn (List .of (achievement ));
583+ given (memberAchievementRepository .findAllByMember (member )).willReturn (List .of ());
584+
585+ // when
586+ var result = myPageService .getAllMyStatsAchievements (1L );
587+
588+ // then
589+ assertThat (result ).hasSize (1 );
590+ assertThat (result .get (0 ).getAchievementName ()).isEqualTo ("첫 업적" );
591+ }
592+
593+ @ Test
594+ @ DisplayName ("성공: 최신 3개 일반 업적 조회" )
595+ void getTop3StatsAchievements_success () {
596+ // given
597+ memberAchievement .setCompleted (true );
598+ memberAchievement .setCompletedAt (LocalDateTime .now ());
599+
600+ given (memberRepository .findById (1L )).willReturn (Optional .of (member ));
601+ given (memberAchievementRepository
602+ .findTop3ByMemberAndCompletedTrueOrderByCompletedAtDescUpdatedAtDesc (member ))
603+ .willReturn (List .of (memberAchievement ));
604+
605+ // when
606+ var result = myPageService .getTop3StatsAchievements (1L );
607+
608+ // then
609+ assertThat (result ).hasSize (1 );
610+ assertThat (result .get (0 ).getAchievementName ()).isEqualTo ("첫 업적" );
611+ }
612+ }
613+
614+ @ Nested
615+ @ DisplayName ("통합 업적 조회 테스트" )
616+ class AllAchievementsTests {
617+
618+ @ Test
619+ @ DisplayName ("성공: 최신 3개 통합 업적 조회" )
620+ void getTop3AllAchievements_success () {
621+ // given
622+ // 일반 업적 달성
623+ memberAchievement .setCompleted (true );
624+ memberAchievement .setCompletedAt (LocalDateTime .now ().minusDays (1 ));
625+
626+ // 챌린지 업적 달성
627+ challengeAchievement .setStep4Goal1Achieved (true );
628+ challengeAchievement .setStep4Goal2Achieved (true );
629+
630+ given (memberRepository .findById (1L )).willReturn (Optional .of (member ));
631+ given (memberAchievementRepository
632+ .findTop3ByMemberAndCompletedTrueOrderByCompletedAtDescUpdatedAtDesc (member ))
633+ .willReturn (List .of (memberAchievement ));
634+ given (challengeAchievementRepository .findByMemberId (1L ))
635+ .willReturn (List .of (challengeAchievement ));
636+ given (challengeRepository .findAllById (any ()))
637+ .willReturn (List .of (challenge ));
638+
639+ // when
640+ var result = myPageService .getTop3AllAchievements (1L );
641+
642+ // then
643+ assertThat (result ).hasSize (2 );
644+ assertThat (result .get (0 ).isCompleted ()).isTrue ();
645+ }
646+ }
330647}
0 commit comments