From cb17a980787b544d03d383d73c45e14c63b978a5 Mon Sep 17 00:00:00 2001 From: chaeyn Date: Fri, 24 Apr 2026 23:04:14 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20mission=EC=9D=98=20content=20?= =?UTF-8?q?=EA=B8=B8=EC=9D=B4=EB=A5=BC=202000=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../persistence/roadmap/v2/question/QuestionV2JpaEntity.java | 2 +- .../question/docs/request/CreateQuestionV2RequestDocument.java | 2 +- .../question/docs/request/UpdateQuestionV2RequestDocument.java | 2 +- .../web/roadmap/v2/question/dto/CreateQuestionV2Dto.java | 2 ++ .../web/roadmap/v2/question/dto/UpdateQuestionV2Dto.java | 2 ++ .../db/migration/V39__increase_question_v2_content_length.sql | 2 ++ 6 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 src/main/resources/db/migration/V39__increase_question_v2_content_length.sql diff --git a/src/main/java/com/process/clash/adapter/persistence/roadmap/v2/question/QuestionV2JpaEntity.java b/src/main/java/com/process/clash/adapter/persistence/roadmap/v2/question/QuestionV2JpaEntity.java index 189f9d8f3..182b4eccf 100644 --- a/src/main/java/com/process/clash/adapter/persistence/roadmap/v2/question/QuestionV2JpaEntity.java +++ b/src/main/java/com/process/clash/adapter/persistence/roadmap/v2/question/QuestionV2JpaEntity.java @@ -32,7 +32,7 @@ public class QuestionV2JpaEntity { @JoinColumn(name = "fk_chapter_id", nullable = false) private ChapterV2JpaEntity chapter; - @Column(nullable = false, length = 1000) + @Column(nullable = false, length = 2000) private String content; private String explanation; diff --git a/src/main/java/com/process/clash/adapter/web/roadmap/v2/question/docs/request/CreateQuestionV2RequestDocument.java b/src/main/java/com/process/clash/adapter/web/roadmap/v2/question/docs/request/CreateQuestionV2RequestDocument.java index 3ac6314ef..9622ac34b 100644 --- a/src/main/java/com/process/clash/adapter/web/roadmap/v2/question/docs/request/CreateQuestionV2RequestDocument.java +++ b/src/main/java/com/process/clash/adapter/web/roadmap/v2/question/docs/request/CreateQuestionV2RequestDocument.java @@ -8,7 +8,7 @@ public class CreateQuestionV2RequestDocument { @Schema(description = "챕터 ID", example = "1") public Long chapterId; - @Schema(description = "문제 내용", example = "자바의 특징이 아닌 것은?") + @Schema(description = "문제 내용", example = "자바의 특징이 아닌 것은?", maxLength = 2000) public String content; @Schema(description = "해설", example = "자바는 객체지향 언어입니다.") diff --git a/src/main/java/com/process/clash/adapter/web/roadmap/v2/question/docs/request/UpdateQuestionV2RequestDocument.java b/src/main/java/com/process/clash/adapter/web/roadmap/v2/question/docs/request/UpdateQuestionV2RequestDocument.java index 6ddcb1a92..5d6549cf9 100644 --- a/src/main/java/com/process/clash/adapter/web/roadmap/v2/question/docs/request/UpdateQuestionV2RequestDocument.java +++ b/src/main/java/com/process/clash/adapter/web/roadmap/v2/question/docs/request/UpdateQuestionV2RequestDocument.java @@ -5,7 +5,7 @@ @Schema(description = "문제 수정 요청") public class UpdateQuestionV2RequestDocument { - @Schema(description = "문제 내용", example = "자바의 주요 특징은?") + @Schema(description = "문제 내용", example = "자바의 주요 특징은?", maxLength = 2000) public String content; @Schema(description = "해설", example = "자바는 객체지향, 플랫폼 독립적, 멀티스레드를 지원합니다.") diff --git a/src/main/java/com/process/clash/adapter/web/roadmap/v2/question/dto/CreateQuestionV2Dto.java b/src/main/java/com/process/clash/adapter/web/roadmap/v2/question/dto/CreateQuestionV2Dto.java index 53615495e..9ba491115 100644 --- a/src/main/java/com/process/clash/adapter/web/roadmap/v2/question/dto/CreateQuestionV2Dto.java +++ b/src/main/java/com/process/clash/adapter/web/roadmap/v2/question/dto/CreateQuestionV2Dto.java @@ -5,6 +5,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; public class CreateQuestionV2Dto { @@ -14,6 +15,7 @@ public record Request( Long chapterId, @NotBlank(message = "content는 필수 입력값입니다.") + @Size(max = 2000, message = "content는 최대 2000자까지 입력할 수 있습니다.") String content, String explanation, diff --git a/src/main/java/com/process/clash/adapter/web/roadmap/v2/question/dto/UpdateQuestionV2Dto.java b/src/main/java/com/process/clash/adapter/web/roadmap/v2/question/dto/UpdateQuestionV2Dto.java index 1b6c67cc8..f0ed8f53b 100644 --- a/src/main/java/com/process/clash/adapter/web/roadmap/v2/question/dto/UpdateQuestionV2Dto.java +++ b/src/main/java/com/process/clash/adapter/web/roadmap/v2/question/dto/UpdateQuestionV2Dto.java @@ -5,12 +5,14 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; public class UpdateQuestionV2Dto { @Schema(name = "UpdateQuestionV2DtoRequest") public record Request( @NotBlank(message = "content는 필수 입력값입니다.") + @Size(max = 2000, message = "content는 최대 2000자까지 입력할 수 있습니다.") String content, String explanation, diff --git a/src/main/resources/db/migration/V39__increase_question_v2_content_length.sql b/src/main/resources/db/migration/V39__increase_question_v2_content_length.sql new file mode 100644 index 000000000..94a4e36c6 --- /dev/null +++ b/src/main/resources/db/migration/V39__increase_question_v2_content_length.sql @@ -0,0 +1,2 @@ +ALTER TABLE questions_v2 + ALTER COLUMN content TYPE VARCHAR(2000); \ No newline at end of file From a3899931ed75b9f7c216d26fcdba1274d0774dbf Mon Sep 17 00:00:00 2001 From: chaeyn Date: Fri, 24 Apr 2026 23:04:51 +0900 Subject: [PATCH 2/3] =?UTF-8?q?test:=20mission=EC=9D=98=20content=20?= =?UTF-8?q?=EA=B8=B8=EC=9D=B4=20=EA=B2=80=EC=A6=9D=20=EB=8B=A8=EC=9C=84=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AdminQuestionV2ControllerTest.java | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 src/test/java/com/process/clash/adapter/web/roadmap/v2/question/controller/AdminQuestionV2ControllerTest.java diff --git a/src/test/java/com/process/clash/adapter/web/roadmap/v2/question/controller/AdminQuestionV2ControllerTest.java b/src/test/java/com/process/clash/adapter/web/roadmap/v2/question/controller/AdminQuestionV2ControllerTest.java new file mode 100644 index 000000000..c00ac2fe9 --- /dev/null +++ b/src/test/java/com/process/clash/adapter/web/roadmap/v2/question/controller/AdminQuestionV2ControllerTest.java @@ -0,0 +1,122 @@ +package com.process.clash.adapter.web.roadmap.v2.question.controller; + +import static org.mockito.Mockito.verifyNoInteractions; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.process.clash.adapter.web.common.GlobalExceptionHandler; +import com.process.clash.adapter.web.security.AuthenticatedActor; +import com.process.clash.application.common.actor.Actor; +import com.process.clash.application.roadmap.v2.question.port.in.CreateQuestionV2UseCase; +import com.process.clash.application.roadmap.v2.question.port.in.DeleteQuestionV2UseCase; +import com.process.clash.application.roadmap.v2.question.port.in.UpdateQuestionV2UseCase; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.core.MethodParameter; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; + +@ExtendWith(MockitoExtension.class) +class AdminQuestionV2ControllerTest { + + @Mock + private CreateQuestionV2UseCase createQuestionV2UseCase; + + @Mock + private UpdateQuestionV2UseCase updateQuestionV2UseCase; + + @Mock + private DeleteQuestionV2UseCase deleteQuestionV2UseCase; + + private final ObjectMapper objectMapper = new ObjectMapper(); + private MockMvc mockMvc; + + @BeforeEach + void setUp() { + AdminQuestionV2Controller controller = new AdminQuestionV2Controller( + createQuestionV2UseCase, + updateQuestionV2UseCase, + deleteQuestionV2UseCase + ); + + LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); + validator.afterPropertiesSet(); + + mockMvc = MockMvcBuilders.standaloneSetup(controller) + .setControllerAdvice(new GlobalExceptionHandler()) + .setCustomArgumentResolvers(authenticatedActorResolver()) + .setValidator(validator) + .build(); + } + + @Test + @DisplayName("POST /api/v2/admin/questions 는 content가 2000자를 초과하면 400을 반환한다") + void createQuestion_whenContentExceeds2000Characters_returnsBadRequest() throws Exception { + mockMvc.perform(post("/api/v2/admin/questions") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(Map.of( + "chapterId", 1L, + "content", "a".repeat(2001), + "explanation", "해설", + "orderIndex", 0, + "difficulty", 1 + )))) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.success").value(false)) + .andExpect(jsonPath("$.error.code").value("INVALID_ARGUMENT")) + .andExpect(jsonPath("$.error.details.content").value("content는 최대 2000자까지 입력할 수 있습니다.")); + + verifyNoInteractions(createQuestionV2UseCase); + } + + @Test + @DisplayName("PATCH /api/v2/admin/questions/{questionId} 는 content가 2000자를 초과하면 400을 반환한다") + void updateQuestion_whenContentExceeds2000Characters_returnsBadRequest() throws Exception { + mockMvc.perform(patch("/api/v2/admin/questions/{questionId}", 1L) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(Map.of( + "content", "a".repeat(2001), + "explanation", "해설", + "orderIndex", 0, + "difficulty", 1 + )))) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.success").value(false)) + .andExpect(jsonPath("$.error.code").value("INVALID_ARGUMENT")) + .andExpect(jsonPath("$.error.details.content").value("content는 최대 2000자까지 입력할 수 있습니다.")); + + verifyNoInteractions(updateQuestionV2UseCase); + } + + private HandlerMethodArgumentResolver authenticatedActorResolver() { + return new HandlerMethodArgumentResolver() { + @Override + public boolean supportsParameter(MethodParameter parameter) { + return parameter.hasParameterAnnotation(AuthenticatedActor.class); + } + + @Override + public Object resolveArgument( + MethodParameter parameter, + ModelAndViewContainer mavContainer, + org.springframework.web.context.request.NativeWebRequest webRequest, + WebDataBinderFactory binderFactory + ) { + return new Actor(1L); + } + }; + } +} From 379d1ea95c2615d77ff505d3131ce0cd9dd88eb8 Mon Sep 17 00:00:00 2001 From: chaeyn Date: Sat, 2 May 2026 20:09:37 +0900 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20=EB=9E=AD=ED=82=B9=20=ED=8B=B0?= =?UTF-8?q?=EC=96=B4=20=EA=B8=B0=EC=A4=80=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/RankingTierUpdateService.java | 8 +-- .../user/userrankhistory/enums/ExpTier.java | 6 +- .../V40__update_ranking_tier_thresholds.sql | 29 ++++++++ .../service/RankingTierUpdateServiceTest.java | 68 +++++++++---------- .../userrankhistory/enums/ExpTierTest.java | 12 ++-- 5 files changed, 76 insertions(+), 47 deletions(-) create mode 100644 src/main/resources/db/migration/V40__update_ranking_tier_thresholds.sql diff --git a/src/main/java/com/process/clash/application/ranking/service/RankingTierUpdateService.java b/src/main/java/com/process/clash/application/ranking/service/RankingTierUpdateService.java index 61a2b88a1..0674ba1a1 100644 --- a/src/main/java/com/process/clash/application/ranking/service/RankingTierUpdateService.java +++ b/src/main/java/com/process/clash/application/ranking/service/RankingTierUpdateService.java @@ -22,8 +22,8 @@ @Slf4j public class RankingTierUpdateService { - private static final int AURA_EXP_THRESHOLD = 200_000; - private static final int MASTER_EXP_THRESHOLD = 150_000; + private static final int AURA_EXP_THRESHOLD = 150_000; + private static final int MASTER_EXP_THRESHOLD = 100_000; private final UserRepositoryPort userRepositoryPort; private final UserRankHistoryRepositoryPort userRankHistoryRepositoryPort; @@ -31,8 +31,8 @@ public class RankingTierUpdateService { /** * 랭킹 기반 티어(Master, Aura) 업데이트 - * - Aura : 1위 && exp >= 200,000 - * - Master: 2~3위 && exp >= 150,000 (상위 3등 2명) + * - Aura : 1위 && exp >= 150,000 + * - Master: 1~3위 && exp >= 100,000 * - 그 외 : NONE */ @Transactional diff --git a/src/main/java/com/process/clash/domain/user/userrankhistory/enums/ExpTier.java b/src/main/java/com/process/clash/domain/user/userrankhistory/enums/ExpTier.java index 09cfaba41..d28fcafd2 100644 --- a/src/main/java/com/process/clash/domain/user/userrankhistory/enums/ExpTier.java +++ b/src/main/java/com/process/clash/domain/user/userrankhistory/enums/ExpTier.java @@ -4,11 +4,11 @@ public enum ExpTier { UNRANKED, // 0 ~ 999 BRONZE, // 1,000 ~ 9,999 SILVER, // 10,000 ~ 29,999 - GOLD, // 30,000 ~ 99,999 - DIAMOND; // 100,000+ + GOLD, // 30,000 ~ 49,999 + DIAMOND; // 50,000+ public static ExpTier fromExp(int exp) { - if (exp >= 100_000) return DIAMOND; + if (exp >= 50_000) return DIAMOND; if (exp >= 30_000) return GOLD; if (exp >= 10_000) return SILVER; if (exp >= 1_000) return BRONZE; diff --git a/src/main/resources/db/migration/V40__update_ranking_tier_thresholds.sql b/src/main/resources/db/migration/V40__update_ranking_tier_thresholds.sql new file mode 100644 index 000000000..9ecd9932d --- /dev/null +++ b/src/main/resources/db/migration/V40__update_ranking_tier_thresholds.sql @@ -0,0 +1,29 @@ +UPDATE users +SET current_exp_tier = CASE + WHEN total_exp >= 50000 THEN 'DIAMOND' + WHEN total_exp >= 30000 THEN 'GOLD' + WHEN total_exp >= 10000 THEN 'SILVER' + WHEN total_exp >= 1000 THEN 'BRONZE' + ELSE 'UNRANKED' +END; + +WITH ranked_users AS ( + SELECT + id, + total_exp, + ROW_NUMBER() OVER (ORDER BY total_exp DESC) AS rank + FROM users + WHERE user_status = 'ACTIVE' +) +UPDATE users u +SET current_rank_tier = CASE + WHEN ru.rank = 1 AND ru.total_exp >= 150000 THEN 'AURA' + WHEN ru.rank <= 3 AND ru.total_exp >= 100000 THEN 'MASTER' + ELSE 'NONE' +END +FROM ranked_users ru +WHERE u.id = ru.id; + +UPDATE users +SET current_rank_tier = 'NONE' +WHERE user_status <> 'ACTIVE'; diff --git a/src/test/java/com/process/clash/application/ranking/service/RankingTierUpdateServiceTest.java b/src/test/java/com/process/clash/application/ranking/service/RankingTierUpdateServiceTest.java index ec27a2f3b..b3cae0bf1 100644 --- a/src/test/java/com/process/clash/application/ranking/service/RankingTierUpdateServiceTest.java +++ b/src/test/java/com/process/clash/application/ranking/service/RankingTierUpdateServiceTest.java @@ -60,9 +60,9 @@ void updateRankTiers_noUsers_doesNothing() { } @Test - @DisplayName("1위이고 exp >= 200000이면 AURA를 부여한다") - void computeRankTier_rank1_expOver200k_returnsAura() { - User user = createUser(1L, 200_000, RankTier.NONE); + @DisplayName("1위이고 exp >= 150000이면 AURA를 부여한다") + void computeRankTier_rank1_expOver150k_returnsAura() { + User user = createUser(1L, 150_000, RankTier.NONE); when(userRepositoryPort.findAllOrderByTotalExpDesc()).thenReturn(List.of(user)); when(seasonRepositoryPort.findCurrentSeason()).thenReturn(Optional.empty()); @@ -74,10 +74,10 @@ void computeRankTier_rank1_expOver200k_returnsAura() { } @Test - @DisplayName("2위이고 exp >= 150000이면 MASTER를 부여한다") - void computeRankTier_rank2_expOver150k_returnsMaster() { - User rank1 = createUser(1L, 250_000, RankTier.NONE); - User rank2 = createUser(2L, 150_000, RankTier.NONE); + @DisplayName("2위이고 exp >= 100000이면 MASTER를 부여한다") + void computeRankTier_rank2_expOver100k_returnsMaster() { + User rank1 = createUser(1L, 150_000, RankTier.NONE); + User rank2 = createUser(2L, 100_000, RankTier.NONE); when(userRepositoryPort.findAllOrderByTotalExpDesc()).thenReturn(List.of(rank1, rank2)); when(seasonRepositoryPort.findCurrentSeason()).thenReturn(Optional.empty()); @@ -91,11 +91,11 @@ void computeRankTier_rank2_expOver150k_returnsMaster() { } @Test - @DisplayName("3위이고 exp >= 150000이면 MASTER를 부여한다") - void computeRankTier_rank3_expOver150k_returnsMaster() { - User rank1 = createUser(1L, 250_000, RankTier.NONE); - User rank2 = createUser(2L, 200_000, RankTier.NONE); - User rank3 = createUser(3L, 150_000, RankTier.NONE); + @DisplayName("3위이고 exp >= 100000이면 MASTER를 부여한다") + void computeRankTier_rank3_expOver100k_returnsMaster() { + User rank1 = createUser(1L, 150_000, RankTier.NONE); + User rank2 = createUser(2L, 120_000, RankTier.NONE); + User rank3 = createUser(3L, 100_000, RankTier.NONE); when(userRepositoryPort.findAllOrderByTotalExpDesc()).thenReturn(List.of(rank1, rank2, rank3)); when(seasonRepositoryPort.findCurrentSeason()).thenReturn(Optional.empty()); @@ -110,10 +110,10 @@ void computeRankTier_rank3_expOver150k_returnsMaster() { @Test @DisplayName("4위이면 exp에 관계없이 NONE을 부여한다") void computeRankTier_rank4_returnsNone() { - User rank1 = createUser(1L, 200_000, RankTier.AURA); - User rank2 = createUser(2L, 180_000, RankTier.MASTER); - User rank3 = createUser(3L, 150_000, RankTier.MASTER); - User rank4 = createUser(4L, 140_000, RankTier.NONE); + User rank1 = createUser(1L, 150_000, RankTier.AURA); + User rank2 = createUser(2L, 120_000, RankTier.MASTER); + User rank3 = createUser(3L, 100_000, RankTier.MASTER); + User rank4 = createUser(4L, 100_000, RankTier.NONE); when(userRepositoryPort.findAllOrderByTotalExpDesc()).thenReturn(List.of(rank1, rank2, rank3, rank4)); when(seasonRepositoryPort.findCurrentSeason()).thenReturn(Optional.empty()); @@ -123,9 +123,9 @@ void computeRankTier_rank4_returnsNone() { } @Test - @DisplayName("1위이지만 exp < 150000이면 NONE을 부여한다") - void computeRankTier_rank1_expUnder150k_returnsNone() { - User user = createUser(1L, 149_999, RankTier.AURA); + @DisplayName("1위이지만 exp < 100000이면 NONE을 부여한다") + void computeRankTier_rank1_expUnder100k_returnsNone() { + User user = createUser(1L, 99_999, RankTier.AURA); when(userRepositoryPort.findAllOrderByTotalExpDesc()).thenReturn(List.of(user)); when(seasonRepositoryPort.findCurrentSeason()).thenReturn(Optional.empty()); @@ -137,9 +137,9 @@ void computeRankTier_rank1_expUnder150k_returnsNone() { } @Test - @DisplayName("1위이고 exp가 150000~199999이면 MASTER를 부여한다") - void computeRankTier_rank1_expBetween150kAnd200k_returnsMaster() { - User user = createUser(1L, 199_999, RankTier.NONE); + @DisplayName("1위이고 exp가 100000~149999이면 MASTER를 부여한다") + void computeRankTier_rank1_expBetween100kAnd150k_returnsMaster() { + User user = createUser(1L, 149_999, RankTier.NONE); when(userRepositoryPort.findAllOrderByTotalExpDesc()).thenReturn(List.of(user)); when(seasonRepositoryPort.findCurrentSeason()).thenReturn(Optional.empty()); @@ -151,10 +151,10 @@ void computeRankTier_rank1_expBetween150kAnd200k_returnsMaster() { } @Test - @DisplayName("2위이지만 exp < 150000이면 NONE을 부여한다") - void computeRankTier_rank2_expUnder150k_returnsNone() { - User rank1 = createUser(1L, 250_000, RankTier.NONE); - User rank2 = createUser(2L, 149_999, RankTier.NONE); + @DisplayName("2위이지만 exp < 100000이면 NONE을 부여한다") + void computeRankTier_rank2_expUnder100k_returnsNone() { + User rank1 = createUser(1L, 150_000, RankTier.NONE); + User rank2 = createUser(2L, 99_999, RankTier.NONE); when(userRepositoryPort.findAllOrderByTotalExpDesc()).thenReturn(List.of(rank1, rank2)); when(seasonRepositoryPort.findCurrentSeason()).thenReturn(Optional.empty()); @@ -169,7 +169,7 @@ void computeRankTier_rank2_expUnder150k_returnsNone() { @Test @DisplayName("티어가 변경되지 않은 유저는 saveAll을 호출하지 않는다") void updateRankTiers_unchangedTier_doesNotSaveUser() { - User user = createUser(1L, 200_000, RankTier.AURA); + User user = createUser(1L, 150_000, RankTier.AURA); when(userRepositoryPort.findAllOrderByTotalExpDesc()).thenReturn(List.of(user)); when(seasonRepositoryPort.findCurrentSeason()).thenReturn(Optional.empty()); @@ -183,8 +183,8 @@ void updateRankTiers_unchangedTier_doesNotSaveUser() { @Test @DisplayName("활성 시즌이 있을 때 모든 유저의 RankHistory를 저장한다") void updateRankTiers_withActiveSeason_savesAllHistories() { - User rank1 = createUser(1L, 200_000, RankTier.NONE); - User rank2 = createUser(2L, 150_000, RankTier.NONE); + User rank1 = createUser(1L, 150_000, RankTier.NONE); + User rank2 = createUser(2L, 100_000, RankTier.NONE); when(userRepositoryPort.findAllOrderByTotalExpDesc()).thenReturn(List.of(rank1, rank2)); when(seasonRepositoryPort.findCurrentSeason()).thenReturn(Optional.of(createSeason(10L))); @@ -198,7 +198,7 @@ void updateRankTiers_withActiveSeason_savesAllHistories() { @Test @DisplayName("활성 시즌이 없을 때 RankHistory를 저장하지 않는다") void updateRankTiers_withoutActiveSeason_doesNotSaveHistory() { - User user = createUser(1L, 200_000, RankTier.NONE); + User user = createUser(1L, 150_000, RankTier.NONE); when(userRepositoryPort.findAllOrderByTotalExpDesc()).thenReturn(List.of(user)); when(seasonRepositoryPort.findCurrentSeason()).thenReturn(Optional.empty()); @@ -210,7 +210,7 @@ void updateRankTiers_withoutActiveSeason_doesNotSaveHistory() { @Test @DisplayName("저장되는 RankHistory의 날짜는 오늘이다") void updateRankTiers_historyDate_isToday() { - User user = createUser(1L, 200_000, RankTier.NONE); + User user = createUser(1L, 150_000, RankTier.NONE); when(userRepositoryPort.findAllOrderByTotalExpDesc()).thenReturn(List.of(user)); when(seasonRepositoryPort.findCurrentSeason()).thenReturn(Optional.of(createSeason(10L))); @@ -238,8 +238,8 @@ void updateRankTiers_expTier_isComputedFromTotalExp() { @Test @DisplayName("RankHistory에 순위와 rankTier가 올바르게 저장된다") void updateRankTiers_historyContainsCorrectRankAndTier() { - User rank1 = createUser(1L, 200_000, RankTier.NONE); - User rank2 = createUser(2L, 150_000, RankTier.NONE); + User rank1 = createUser(1L, 150_000, RankTier.NONE); + User rank2 = createUser(2L, 100_000, RankTier.NONE); when(userRepositoryPort.findAllOrderByTotalExpDesc()).thenReturn(List.of(rank1, rank2)); when(seasonRepositoryPort.findCurrentSeason()).thenReturn(Optional.of(createSeason(10L))); @@ -258,7 +258,7 @@ void updateRankTiers_historyContainsCorrectRankAndTier() { @Test @DisplayName("RankHistory의 seasonId는 현재 시즌 id로 저장된다") void updateRankTiers_historySeasonId_matchesCurrentSeason() { - User user = createUser(1L, 200_000, RankTier.NONE); + User user = createUser(1L, 150_000, RankTier.NONE); Season season = createSeason(42L); when(userRepositoryPort.findAllOrderByTotalExpDesc()).thenReturn(List.of(user)); when(seasonRepositoryPort.findCurrentSeason()).thenReturn(Optional.of(season)); diff --git a/src/test/java/com/process/clash/domain/user/userrankhistory/enums/ExpTierTest.java b/src/test/java/com/process/clash/domain/user/userrankhistory/enums/ExpTierTest.java index c24a0f204..89b93ddf1 100644 --- a/src/test/java/com/process/clash/domain/user/userrankhistory/enums/ExpTierTest.java +++ b/src/test/java/com/process/clash/domain/user/userrankhistory/enums/ExpTierTest.java @@ -8,14 +8,14 @@ class ExpTierTest { @Test - @DisplayName("exp가 100000 이상이면 DIAMOND다") - void fromExp_overOrEqual100k_returnsDiamond() { - assertThat(ExpTier.fromExp(100_000)).isEqualTo(ExpTier.DIAMOND); + @DisplayName("exp가 50000 이상이면 DIAMOND다") + void fromExp_overOrEqual50k_returnsDiamond() { + assertThat(ExpTier.fromExp(50_000)).isEqualTo(ExpTier.DIAMOND); } @Test - @DisplayName("exp가 99999 이하이면 GOLD다") - void fromExp_under100k_returnsGold() { - assertThat(ExpTier.fromExp(99_999)).isEqualTo(ExpTier.GOLD); + @DisplayName("exp가 49999 이하이면 GOLD다") + void fromExp_under50k_returnsGold() { + assertThat(ExpTier.fromExp(49_999)).isEqualTo(ExpTier.GOLD); } }