Skip to content

Commit 60c5f85

Browse files
authored
fix : 레벨업 시 생길 수 있는 예외 사항 개선 (#132)
1 parent db19c63 commit 60c5f85

File tree

2 files changed

+86
-30
lines changed

2 files changed

+86
-30
lines changed

backend/src/main/java/com/back/domain/level/service/LevelUpService.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,10 @@ public void checkAndProcessLevelUp(Member member) {
9393
// 3. 레벨업 보상 지급
9494
List<Reward> rewards = rewardService.findByRewardTypeAndRequireValue(RewardType.LEVELUP, currentLevel);
9595
if (!rewards.isEmpty()) {
96-
rewardService.giveReward(member.getId(), currentLevel, rewards.getFirst().getId());
96+
for (Reward reward : rewards) {
97+
rewardService.giveReward(member.getId(), currentLevel, reward.getId());
98+
log.info(" [Reward Given] Given Reward ID {} for reaching Level {}", reward.getId(), currentLevel);
99+
}
97100
}
98101
}
99102
}

backend/src/test/java/com/back/domain/level/LevelUpServiceTest.java

Lines changed: 82 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,24 @@
55
import com.back.domain.level.service.LevelUpService;
66
import com.back.domain.member.entity.Member;
77
import com.back.domain.member.repository.MemberRepository;
8+
import com.back.domain.reward.entity.ContentType;
9+
import com.back.domain.reward.entity.Reward;
10+
import com.back.domain.reward.entity.RewardContent;
11+
import com.back.domain.reward.entity.RewardType;
812
import com.back.domain.reward.repository.RewardRepository;
13+
import com.back.domain.title.dto.CreateTitleDto;
14+
import com.back.domain.title.dto.TitleDto;
15+
import com.back.domain.title.service.TitleService;
916
import org.junit.jupiter.api.BeforeEach;
1017
import org.junit.jupiter.api.DisplayName;
1118
import org.junit.jupiter.api.Test;
1219
import org.springframework.beans.factory.annotation.Autowired;
1320
import org.springframework.boot.test.context.SpringBootTest;
1421
import org.springframework.transaction.annotation.Transactional;
1522

23+
import java.util.ArrayList;
24+
import java.util.HashSet;
25+
import java.util.List;
1626
import java.util.Optional;
1727

1828
import static org.assertj.core.api.Assertions.assertThat;
@@ -25,7 +35,7 @@ class LevelUpServiceTest {
2535
@Autowired private MemberRepository memberRepository;
2636
@Autowired private LevelXPRepository levelXPRepository;
2737
@Autowired private RewardRepository rewardRepository;
28-
38+
@Autowired private TitleService titleService;
2939

3040
// 테스트용 상수 정의
3141
private final int INITIAL_LEVEL = 1;
@@ -43,33 +53,54 @@ class LevelUpServiceTest {
4353
// Level 2 달성에 필요한 총 XP (요구치 1500 + 초과분 500 = 2000)
4454
private final int XP_FOR_LEVELUP_AND_EXCESS = XP_TO_LEVEL2 + EXCESS_XP;
4555

56+
// 테스트용 칭호 ID
57+
private int testTitleId;
4658

4759
@BeforeEach
4860
void setupData() {
49-
// LevelXP 데이터를 현재 레벨 XP 로직에 맞게 설정
61+
// 모든 데이터 초기화
5062
levelXPRepository.deleteAll();
63+
rewardRepository.deleteAll();
5164

52-
// Level 1 데이터: Level 2로 가는데 1500 필요
65+
// 1. LevelXP 데이터 설정
5366
levelXPRepository.save(new LevelXP(INITIAL_LEVEL, XP_TO_LEVEL2));
54-
// Level 2 데이터: Level 3으로 가는데 2000 필요
5567
levelXPRepository.save(new LevelXP(NEXT_LEVEL, XP_TO_LEVEL3));
5668

57-
// 레벨업 보상 지급 로직을 회피하기 위해 Reward 데이터를 삭제합니다.
58-
rewardRepository.deleteAll();
69+
// 2. 테스트용 칭호 생성 및 ID 저장
70+
TitleDto createdTitle = titleService.createTitle(new CreateTitleDto("테스트 칭호", "레벨 2 달성", "테스트용 캡션"));
71+
testTitleId = createdTitle.id();
72+
73+
// 3. LevelUp Reward 데이터 설정
74+
List<RewardContent> titleRewardContents = new ArrayList<>();
75+
titleRewardContents.add(new RewardContent(ContentType.TITLE, testTitleId));
76+
77+
// Level 2 달성을 요구하는 LEVELUP 보상 생성 (requireValue: 2)
78+
Reward reward = new Reward(RewardType.LEVELUP, titleRewardContents, NEXT_LEVEL);
79+
rewardRepository.save(reward);
80+
}
81+
82+
private Member createTestMember(int level, int xp, int xpReq) {
83+
Member member = Member.builder()
84+
.level(level)
85+
.xp(xp)
86+
.xpReq(xpReq)
87+
.money(0)
88+
.build();
89+
if (member.getOwnedTitles() == null) {
90+
member.setOwnedTitles(new HashSet<>());
91+
}
92+
if (member.getOwnedItems() == null) {
93+
member.setOwnedItems(new HashSet<>());
94+
}
95+
return memberRepository.save(member);
5996
}
6097

6198

6299
@Test
63100
@DisplayName("XP 요구치 충족 시 레벨업이 발생하고, 초과 경험치가 다음 레벨로 이월되며, 다음 xpReq가 업데이트된다")
64101
void checkLevelUp_ShouldLevelUp_WithExcessXP() {
65102
// GIVEN
66-
Member member = Member.builder()
67-
.level(INITIAL_LEVEL)
68-
.xp(INITIAL_XP) // INITIAL_XP = 0
69-
.xpReq(XP_TO_LEVEL2) // Level 2 요구 XP
70-
.money(0) // 돈은 검증 대상이 아님
71-
.build();
72-
member = memberRepository.save(member);
103+
Member member = createTestMember(INITIAL_LEVEL, INITIAL_XP, XP_TO_LEVEL2);
73104
Integer memberId = member.getId();
74105

75106
// 레벨업에 충분한 XP를 수동으로 설정
@@ -93,17 +124,47 @@ void checkLevelUp_ShouldLevelUp_WithExcessXP() {
93124
}
94125

95126

127+
@Test
128+
@DisplayName("XP 요구치 충족 시 레벨업이 발생하고, 레벨업 보상으로 칭호가 제대로 지급된다")
129+
void checkLevelUp_ShouldLevelUp_AndGiveTitleReward() {
130+
// GIVEN
131+
Member member = createTestMember(INITIAL_LEVEL, INITIAL_XP, XP_TO_LEVEL2);
132+
Integer memberId = member.getId();
133+
134+
// 초기에는 칭호를 가지고 있지 않아야 합니다.
135+
assertThat(member.getOwnedTitles()).isEmpty();
136+
137+
// 레벨업에 충분한 XP를 수동으로 설정
138+
member.setXp(XP_FOR_LEVELUP_AND_EXCESS); // member.xp = 2000
139+
memberRepository.save(member);
140+
141+
// WHEN
142+
levelUpService.checkLevelUp(memberId);
143+
144+
// THEN
145+
Optional<Member> updatedMemberOpt = memberRepository.findById(memberId);
146+
assertThat(updatedMemberOpt).isPresent();
147+
Member updatedMember = updatedMemberOpt.get();
148+
149+
// 1. 레벨업 확인
150+
assertThat(updatedMember.getLevel()).isEqualTo(NEXT_LEVEL); // Level 2로 레벨업
151+
152+
// 2. 칭호 지급 확인 (핵심 검증)
153+
// 획득한 칭호 Set이 비어있지 않고, 그 크기가 1인지 확인
154+
assertThat(updatedMember.getOwnedTitles()).hasSize(1);
155+
156+
// 획득한 칭호의 ID가 테스트용으로 생성한 칭호 ID와 일치하는지 확인
157+
assertThat(updatedMember.getOwnedTitles().stream().anyMatch(title -> title.getId() == testTitleId)).isTrue();
158+
159+
// 3. XP 이월 확인
160+
assertThat(updatedMember.getXp()).isEqualTo(EXCESS_XP);
161+
}
162+
96163
@Test
97164
@DisplayName("XP가 레벨업 요구치에 미달하면 레벨 및 XP 변화가 없다")
98165
void checkLevelUp_ShouldNotLevelUp_NoChange() {
99166
// GIVEN
100-
Member member = Member.builder()
101-
.level(INITIAL_LEVEL)
102-
.xp(INITIAL_XP)
103-
.xpReq(XP_TO_LEVEL2)
104-
.money(0)
105-
.build();
106-
member = memberRepository.save(member);
167+
Member member = createTestMember(INITIAL_LEVEL, INITIAL_XP, XP_TO_LEVEL2);
107168
Integer memberId = member.getId();
108169

109170
// 레벨업에 부족한 XP를 설정 (요구치 1500 미만인 1499 설정)
@@ -129,17 +190,10 @@ void checkLevelUp_ShouldNotLevelUp_NoChange() {
129190
@DisplayName("충분한 XP를 부여하여 다중 레벨업이 연속적으로 발생하고, 최종 XP가 이월된다")
130191
void checkLevelUp_ShouldHandleMultipleLevelUps() {
131192
// GIVEN
132-
133193
// Level 1 -> 2 -> 3 연속 레벨업을 위한 충분한 XP 계산
134194
int totalXpForMultipleLevelUp = XP_TO_LEVEL2 + XP_TO_LEVEL3 + EXCESS_XP; // 1500 + 2000 + 500 = 4000
135195

136-
Member member = Member.builder()
137-
.level(INITIAL_LEVEL)
138-
.xp(INITIAL_XP)
139-
.xpReq(XP_TO_LEVEL2)
140-
.money(0)
141-
.build();
142-
member = memberRepository.save(member);
196+
Member member = createTestMember(INITIAL_LEVEL, INITIAL_XP, XP_TO_LEVEL2);
143197
Integer memberId = member.getId();
144198

145199
member.setXp(totalXpForMultipleLevelUp); // member.xp = 4000
@@ -165,5 +219,4 @@ void checkLevelUp_ShouldHandleMultipleLevelUps() {
165219
// 3. 다음 요구 XP 확인
166220
assertThat(updatedMember.getXpReq()).isEqualTo(XP_TO_LEVEL4); // Level 4 요구량
167221
}
168-
169222
}

0 commit comments

Comments
 (0)