From 8ccebbf755061ee5f5729148b5fc1d500a4b192a Mon Sep 17 00:00:00 2001 From: Sumin Date: Fri, 7 Feb 2025 15:11:51 +0900 Subject: [PATCH 01/18] =?UTF-8?q?feat:=20=EC=A6=90=EA=B2=A8=EC=B0=BE?= =?UTF-8?q?=EA=B8=B0=20=EC=97=94=ED=8B=B0=ED=8B=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/kr/allcll/seatfinder/star/Star.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/main/java/kr/allcll/seatfinder/star/Star.java diff --git a/src/main/java/kr/allcll/seatfinder/star/Star.java b/src/main/java/kr/allcll/seatfinder/star/Star.java new file mode 100644 index 0000000..20af4da --- /dev/null +++ b/src/main/java/kr/allcll/seatfinder/star/Star.java @@ -0,0 +1,32 @@ +package kr.allcll.seatfinder.star; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import kr.allcll.seatfinder.subject.Subject; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Table(name = "star") +@Entity +@Getter +@NoArgsConstructor +public class Star { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "token") + private String token; + + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "subject_id", nullable = false) + private Subject subject; +} From af4072ffacf56edb0c576fcdc9a8a98d1f87f631 Mon Sep 17 00:00:00 2001 From: Sumin Date: Fri, 7 Feb 2025 17:26:39 +0900 Subject: [PATCH 02/18] =?UTF-8?q?refactor:=20=EC=A6=90=EA=B2=A8=EC=B0=BE?= =?UTF-8?q?=EA=B8=B0=20=EC=97=94=ED=8B=B0=ED=8B=B0=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=EC=9E=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/kr/allcll/seatfinder/star/Star.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/kr/allcll/seatfinder/star/Star.java b/src/main/java/kr/allcll/seatfinder/star/Star.java index 20af4da..5720717 100644 --- a/src/main/java/kr/allcll/seatfinder/star/Star.java +++ b/src/main/java/kr/allcll/seatfinder/star/Star.java @@ -29,4 +29,9 @@ public class Star { @ManyToOne(fetch = FetchType.LAZY, optional = false) @JoinColumn(name = "subject_id", nullable = false) private Subject subject; + + public Star(String token, Subject subject) { + this.token = token; + this.subject = subject; + } } From fbf51f55d7d06c6dab7b2987460c190dc1275365 Mon Sep 17 00:00:00 2001 From: Sumin Date: Fri, 7 Feb 2025 17:26:59 +0900 Subject: [PATCH 03/18] =?UTF-8?q?feat:=20=EC=A6=90=EA=B2=A8=EC=B0=BE?= =?UTF-8?q?=EA=B8=B0=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../seatfinder/exception/AllcllErrorCode.java | 2 + .../kr/allcll/seatfinder/star/StarApi.java | 21 ++++++++++ .../seatfinder/star/StarRepository.java | 12 ++++++ .../allcll/seatfinder/star/StarService.java | 39 +++++++++++++++++++ 4 files changed, 74 insertions(+) create mode 100644 src/main/java/kr/allcll/seatfinder/star/StarApi.java create mode 100644 src/main/java/kr/allcll/seatfinder/star/StarRepository.java create mode 100644 src/main/java/kr/allcll/seatfinder/star/StarService.java diff --git a/src/main/java/kr/allcll/seatfinder/exception/AllcllErrorCode.java b/src/main/java/kr/allcll/seatfinder/exception/AllcllErrorCode.java index acb97ed..77f0d1f 100644 --- a/src/main/java/kr/allcll/seatfinder/exception/AllcllErrorCode.java +++ b/src/main/java/kr/allcll/seatfinder/exception/AllcllErrorCode.java @@ -3,7 +3,9 @@ public enum AllcllErrorCode { PIN_LIMIT_EXCEEDED("이미 %d개의 핀을 등록했습니다."), + STAR_LIMIT_EXCEEDED("이미 %d개의 즐겨찾기를 등록했습니다."), DUPLICATE_PIN("%s은(는) 이미 핀 등록된 과목입니다."), + DUPLICATE_STAR("%s은(는) 이미 핀 등록된 과목입니다."), PIN_SUBJECT_MISMATCH("핀에 등록된 과목이 아닙니다."), TOKEN_NOT_FOUND("쿠키에 토큰이 존재하지 않습니다."), SUBJECT_NOT_FOUND("존재하지 않는 과목 입니다."); diff --git a/src/main/java/kr/allcll/seatfinder/star/StarApi.java b/src/main/java/kr/allcll/seatfinder/star/StarApi.java new file mode 100644 index 0000000..efd717b --- /dev/null +++ b/src/main/java/kr/allcll/seatfinder/star/StarApi.java @@ -0,0 +1,21 @@ +package kr.allcll.seatfinder.star; + +import kr.allcll.seatfinder.ThreadLocalHolder; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +public class StarApi { + + private final StarService starService; + + @PostMapping("/api/stars") + ResponseEntity addStarOnSubject(@RequestParam Long subjectId) { + starService.addStarOnSubject(subjectId, ThreadLocalHolder.SHARED_TOKEN.get()); + return ResponseEntity.ok().build(); + } +} diff --git a/src/main/java/kr/allcll/seatfinder/star/StarRepository.java b/src/main/java/kr/allcll/seatfinder/star/StarRepository.java new file mode 100644 index 0000000..f02c61b --- /dev/null +++ b/src/main/java/kr/allcll/seatfinder/star/StarRepository.java @@ -0,0 +1,12 @@ +package kr.allcll.seatfinder.star; + +import java.util.List; +import kr.allcll.seatfinder.subject.Subject; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface StarRepository extends JpaRepository { + + boolean existsBySubjectAndToken(Subject subject, String token); + + List findAllByToken(String token); +} diff --git a/src/main/java/kr/allcll/seatfinder/star/StarService.java b/src/main/java/kr/allcll/seatfinder/star/StarService.java new file mode 100644 index 0000000..5f13bc7 --- /dev/null +++ b/src/main/java/kr/allcll/seatfinder/star/StarService.java @@ -0,0 +1,39 @@ +package kr.allcll.seatfinder.star; + +import java.util.List; +import kr.allcll.seatfinder.exception.AllcllErrorCode; +import kr.allcll.seatfinder.exception.AllcllException; +import kr.allcll.seatfinder.subject.Subject; +import kr.allcll.seatfinder.subject.SubjectRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class StarService { + + private static final int MAX_PIN_NUMBER = 5; + + private final StarRepository starRepository; + private final SubjectRepository subjectRepository; + + @Transactional + public void addStarOnSubject(Long subjectId, String token) { + List starsByToken = starRepository.findAllByToken(token); + Subject subject = subjectRepository.findById(subjectId) + .orElseThrow(() -> new AllcllException(AllcllErrorCode.SUBJECT_NOT_FOUND)); + validateCanAddStar(starsByToken, subject, token); + starRepository.save(new Star(token, subject)); + } + + private void validateCanAddStar(List userStars, Subject subject, String token) { + if (userStars.size() >= MAX_PIN_NUMBER) { + throw new AllcllException(AllcllErrorCode.STAR_LIMIT_EXCEEDED, MAX_PIN_NUMBER); + } + if (starRepository.existsBySubjectAndToken(subject, token)) { + throw new AllcllException(AllcllErrorCode.DUPLICATE_STAR, subject.getCuriNm()); + } + } +} From 61e384920fd6594ab7bb43fb07ae509702669e79 Mon Sep 17 00:00:00 2001 From: Sumin Date: Fri, 7 Feb 2025 17:27:14 +0900 Subject: [PATCH 04/18] =?UTF-8?q?test:=20=EC=A6=90=EA=B2=A8=EC=B0=BE?= =?UTF-8?q?=EA=B8=B0=20=EC=B6=94=EA=B0=80=20=EA=B8=B0=EB=8A=A5=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../seatfinder/star/StarServiceTest.java | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java diff --git a/src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java b/src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java new file mode 100644 index 0000000..8c9a0cb --- /dev/null +++ b/src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java @@ -0,0 +1,95 @@ +package kr.allcll.seatfinder.star; + +import static kr.allcll.seatfinder.support.fixture.SubjectFixture.createSubject; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.List; +import kr.allcll.seatfinder.exception.AllcllErrorCode; +import kr.allcll.seatfinder.exception.AllcllException; +import kr.allcll.seatfinder.subject.Subject; +import kr.allcll.seatfinder.subject.SubjectRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; + +@SpringBootTest(webEnvironment = WebEnvironment.NONE) +class StarServiceTest { + + private static final int MAX_STAR_NUMBER = 5; + private static final String TOKEN = "token"; + + @Autowired + private StarService starService; + + @Autowired + private SubjectRepository subjectRepository; + + @Autowired + private StarRepository starRepository; + + @BeforeEach + void setUp() { + starRepository.deleteAllInBatch(); + subjectRepository.deleteAllInBatch(); + } + + @Test + @DisplayName("즐겨찾기 5개 미만일 경우 정상 등록을 검증한다.") + void addStarOnProject() { + // given + Subject subjectA = createSubject("컴퓨터구조", "003278", "001", "김보예"); + subjectRepository.save(subjectA); + starService.addStarOnSubject(subjectA.getId(), TOKEN); + + // when + List result = starRepository.findAllByToken(TOKEN); + + // then + assertThat(result).hasSize(1); + } + + @Test + @DisplayName("즐겨찾기가 5개 이상일 경우 예외를 검증한다.") + void canNotAddStarOnSubject() { + // given + Subject subjectA = createSubject("컴퓨터구조", "003278", "001", "김보예"); + Subject subjectB = createSubject("운영체제", "003279", "001", "김수민"); + Subject subjectC = createSubject("자료구조", "003280", "001", "김봉케"); + Subject subjectD = createSubject("알고리즘", "003281", "001", "오현지"); + Subject subjectE = createSubject("컴퓨터구조", "003278", "002", "전유채"); + Subject overCountSubject = createSubject("컴퓨터구조", "003278", "002", "전유채"); + subjectRepository.saveAll(List.of(subjectA, subjectB, subjectC, subjectD, subjectE, overCountSubject)); + starRepository.saveAll( + List.of( + new Star(TOKEN, subjectA), + new Star(TOKEN, subjectB), + new Star(TOKEN, subjectC), + new Star(TOKEN, subjectD), + new Star(TOKEN, subjectE)) + ); + + // when, then + assertThatThrownBy(() -> starService.addStarOnSubject(overCountSubject.getId(), TOKEN)) + .isInstanceOf(AllcllException.class) + .hasMessageContaining(String.format(AllcllErrorCode.STAR_LIMIT_EXCEEDED.getMessage(), MAX_STAR_NUMBER)); + } + + @Test + @DisplayName("이미 즐겨찾기 등록된 과목일 경우 예외를 검증한다.") + void alreadyExistStarSubject() { + // given + Subject subject = createSubject("컴퓨터구조", "003278", "001", "김보예"); + subjectRepository.save(subject); + starRepository.save(new Star(TOKEN, subject)); + String expectExceptionMessage = new AllcllException(AllcllErrorCode.DUPLICATE_STAR, "컴퓨터구조").getMessage(); + + // when, then + assertThatThrownBy(() -> starService.addStarOnSubject(subject.getId(), TOKEN)) + .isInstanceOf(AllcllException.class) + .hasMessageContaining(expectExceptionMessage); + } +} From 86ac01c952bbf71795349c6bfb7749afef991680 Mon Sep 17 00:00:00 2001 From: Sumin Date: Fri, 7 Feb 2025 17:50:55 +0900 Subject: [PATCH 05/18] =?UTF-8?q?refactor:=20=EC=A6=90=EA=B2=A8=EC=B0=BE?= =?UTF-8?q?=EA=B8=B0=20=EC=B5=9C=EB=8C=80=20=EA=B0=9C=EC=88=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/kr/allcll/seatfinder/star/StarService.java | 6 +++--- .../java/kr/allcll/seatfinder/star/StarServiceTest.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/kr/allcll/seatfinder/star/StarService.java b/src/main/java/kr/allcll/seatfinder/star/StarService.java index 5f13bc7..e5d9f07 100644 --- a/src/main/java/kr/allcll/seatfinder/star/StarService.java +++ b/src/main/java/kr/allcll/seatfinder/star/StarService.java @@ -14,7 +14,7 @@ @RequiredArgsConstructor public class StarService { - private static final int MAX_PIN_NUMBER = 5; + private static final int MAX_STAR_NUMBER = 10; private final StarRepository starRepository; private final SubjectRepository subjectRepository; @@ -29,8 +29,8 @@ public void addStarOnSubject(Long subjectId, String token) { } private void validateCanAddStar(List userStars, Subject subject, String token) { - if (userStars.size() >= MAX_PIN_NUMBER) { - throw new AllcllException(AllcllErrorCode.STAR_LIMIT_EXCEEDED, MAX_PIN_NUMBER); + if (userStars.size() >= MAX_STAR_NUMBER) { + throw new AllcllException(AllcllErrorCode.STAR_LIMIT_EXCEEDED, MAX_STAR_NUMBER); } if (starRepository.existsBySubjectAndToken(subject, token)) { throw new AllcllException(AllcllErrorCode.DUPLICATE_STAR, subject.getCuriNm()); diff --git a/src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java b/src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java index 8c9a0cb..3060733 100644 --- a/src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java +++ b/src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java @@ -19,7 +19,7 @@ @SpringBootTest(webEnvironment = WebEnvironment.NONE) class StarServiceTest { - private static final int MAX_STAR_NUMBER = 5; + private static final int MAX_STAR_NUMBER = 10; private static final String TOKEN = "token"; @Autowired From 45b531b92c373690727d17b3a239cc36d3518047 Mon Sep 17 00:00:00 2001 From: Sumin Date: Fri, 7 Feb 2025 18:18:08 +0900 Subject: [PATCH 06/18] =?UTF-8?q?feat:=20=EC=A6=90=EA=B2=A8=EC=B0=BE?= =?UTF-8?q?=EA=B8=B0=20=EC=A1=B0=ED=9A=8C=20=EB=B0=8F=20=EC=82=AD=EC=A0=9C?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../seatfinder/exception/AllcllErrorCode.java | 1 + .../kr/allcll/seatfinder/star/StarApi.java | 16 ++++++++++++++++ .../allcll/seatfinder/star/StarRepository.java | 3 +++ .../kr/allcll/seatfinder/star/StarService.java | 18 ++++++++++++++++++ 4 files changed, 38 insertions(+) diff --git a/src/main/java/kr/allcll/seatfinder/exception/AllcllErrorCode.java b/src/main/java/kr/allcll/seatfinder/exception/AllcllErrorCode.java index 77f0d1f..f5ecee7 100644 --- a/src/main/java/kr/allcll/seatfinder/exception/AllcllErrorCode.java +++ b/src/main/java/kr/allcll/seatfinder/exception/AllcllErrorCode.java @@ -7,6 +7,7 @@ public enum AllcllErrorCode { DUPLICATE_PIN("%s은(는) 이미 핀 등록된 과목입니다."), DUPLICATE_STAR("%s은(는) 이미 핀 등록된 과목입니다."), PIN_SUBJECT_MISMATCH("핀에 등록된 과목이 아닙니다."), + STAR_SUBJECT_MISMATCH("즐겨찾기에 등록된 과목이 아닙니다."), TOKEN_NOT_FOUND("쿠키에 토큰이 존재하지 않습니다."), SUBJECT_NOT_FOUND("존재하지 않는 과목 입니다."); diff --git a/src/main/java/kr/allcll/seatfinder/star/StarApi.java b/src/main/java/kr/allcll/seatfinder/star/StarApi.java index efd717b..0d2dc65 100644 --- a/src/main/java/kr/allcll/seatfinder/star/StarApi.java +++ b/src/main/java/kr/allcll/seatfinder/star/StarApi.java @@ -1,8 +1,12 @@ package kr.allcll.seatfinder.star; import kr.allcll.seatfinder.ThreadLocalHolder; +import kr.allcll.seatfinder.pin.dto.SubjectIdsResponse; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -18,4 +22,16 @@ ResponseEntity addStarOnSubject(@RequestParam Long subjectId) { starService.addStarOnSubject(subjectId, ThreadLocalHolder.SHARED_TOKEN.get()); return ResponseEntity.ok().build(); } + + @DeleteMapping("/api/stars/{subjectId}") + public ResponseEntity deleteStarOnSubject(@PathVariable Long subjectId) { + starService.deleteStarOnSubject(subjectId, ThreadLocalHolder.SHARED_TOKEN.get()); + return ResponseEntity.ok().build(); + } + + @GetMapping("/api/stars") + public ResponseEntity retrieveStars() { + SubjectIdsResponse response = starService.retrieveStars(ThreadLocalHolder.SHARED_TOKEN.get()); + return ResponseEntity.ok(response); + } } diff --git a/src/main/java/kr/allcll/seatfinder/star/StarRepository.java b/src/main/java/kr/allcll/seatfinder/star/StarRepository.java index f02c61b..5049bf9 100644 --- a/src/main/java/kr/allcll/seatfinder/star/StarRepository.java +++ b/src/main/java/kr/allcll/seatfinder/star/StarRepository.java @@ -1,6 +1,7 @@ package kr.allcll.seatfinder.star; import java.util.List; +import java.util.Optional; import kr.allcll.seatfinder.subject.Subject; import org.springframework.data.jpa.repository.JpaRepository; @@ -9,4 +10,6 @@ public interface StarRepository extends JpaRepository { boolean existsBySubjectAndToken(Subject subject, String token); List findAllByToken(String token); + + Optional findBySubjectAndToken(Subject subject, String token); } diff --git a/src/main/java/kr/allcll/seatfinder/star/StarService.java b/src/main/java/kr/allcll/seatfinder/star/StarService.java index e5d9f07..ae6dd6d 100644 --- a/src/main/java/kr/allcll/seatfinder/star/StarService.java +++ b/src/main/java/kr/allcll/seatfinder/star/StarService.java @@ -3,6 +3,8 @@ import java.util.List; import kr.allcll.seatfinder.exception.AllcllErrorCode; import kr.allcll.seatfinder.exception.AllcllException; +import kr.allcll.seatfinder.pin.dto.SubjectIdResponse; +import kr.allcll.seatfinder.pin.dto.SubjectIdsResponse; import kr.allcll.seatfinder.subject.Subject; import kr.allcll.seatfinder.subject.SubjectRepository; import lombok.RequiredArgsConstructor; @@ -36,4 +38,20 @@ private void validateCanAddStar(List userStars, Subject subject, String to throw new AllcllException(AllcllErrorCode.DUPLICATE_STAR, subject.getCuriNm()); } } + + @Transactional + public void deleteStarOnSubject(Long subjectId, String token) { + Subject subject = subjectRepository.findById(subjectId) + .orElseThrow(() -> new AllcllException(AllcllErrorCode.SUBJECT_NOT_FOUND)); + Star star = starRepository.findBySubjectAndToken(subject, token) + .orElseThrow(() -> new AllcllException(AllcllErrorCode.STAR_SUBJECT_MISMATCH)); + starRepository.deleteById(star.getId()); + } + + public SubjectIdsResponse retrieveStars(String token) { + List stars = starRepository.findAllByToken(token); + return new SubjectIdsResponse(stars.stream() + .map(star -> new SubjectIdResponse(star.getSubject().getId())) + .toList()); + } } From 25ad7db3333abfd911cbd6a04e8b7257e447a341 Mon Sep 17 00:00:00 2001 From: Sumin Date: Fri, 7 Feb 2025 18:18:23 +0900 Subject: [PATCH 07/18] =?UTF-8?q?test:=20=EC=A6=90=EA=B2=A8=EC=B0=BE?= =?UTF-8?q?=EA=B8=B0=20=EC=A1=B0=ED=9A=8C=20=EB=B0=8F=20=EC=82=AD=EC=A0=9C?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../seatfinder/star/StarServiceTest.java | 107 ++++++++++++++++-- 1 file changed, 99 insertions(+), 8 deletions(-) diff --git a/src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java b/src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java index 3060733..16bc6a0 100644 --- a/src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java +++ b/src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java @@ -7,6 +7,7 @@ import java.util.List; import kr.allcll.seatfinder.exception.AllcllErrorCode; import kr.allcll.seatfinder.exception.AllcllException; +import kr.allcll.seatfinder.pin.dto.SubjectIdsResponse; import kr.allcll.seatfinder.subject.Subject; import kr.allcll.seatfinder.subject.SubjectRepository; import org.junit.jupiter.api.BeforeEach; @@ -56,26 +57,44 @@ void addStarOnProject() { @DisplayName("즐겨찾기가 5개 이상일 경우 예외를 검증한다.") void canNotAddStarOnSubject() { // given + Subject overCountSubject = createSubject("컴퓨터구조", "003278", "005", "김수민"); + subjectRepository.save(overCountSubject); + saveSubjectsAndTenStars(); + + // when, then + assertThatThrownBy(() -> starService.addStarOnSubject(overCountSubject.getId(), TOKEN)) + .isInstanceOf(AllcllException.class) + .hasMessageContaining(String.format(AllcllErrorCode.STAR_LIMIT_EXCEEDED.getMessage(), MAX_STAR_NUMBER)); + } + + private void saveSubjectsAndTenStars() { Subject subjectA = createSubject("컴퓨터구조", "003278", "001", "김보예"); Subject subjectB = createSubject("운영체제", "003279", "001", "김수민"); Subject subjectC = createSubject("자료구조", "003280", "001", "김봉케"); Subject subjectD = createSubject("알고리즘", "003281", "001", "오현지"); Subject subjectE = createSubject("컴퓨터구조", "003278", "002", "전유채"); - Subject overCountSubject = createSubject("컴퓨터구조", "003278", "002", "전유채"); - subjectRepository.saveAll(List.of(subjectA, subjectB, subjectC, subjectD, subjectE, overCountSubject)); + Subject subjectF = createSubject("과목6", "003279", "003", "전유채"); + Subject subjectG = createSubject("과목7", "003270", "002", "김주환"); + Subject subjectH = createSubject("운영체제", "113278", "001", "김뽀예"); + Subject subjectI = createSubject("컴퓨터구조", "003278", "002", "전유채"); + Subject subjectJ = createSubject("자료구조", "003272", "001", "박희준"); + subjectRepository.saveAll( + List.of(subjectA, subjectB, subjectC, subjectD, subjectE, subjectF, + subjectG, subjectH, subjectI, subjectJ)); starRepository.saveAll( List.of( new Star(TOKEN, subjectA), new Star(TOKEN, subjectB), new Star(TOKEN, subjectC), new Star(TOKEN, subjectD), - new Star(TOKEN, subjectE)) + new Star(TOKEN, subjectE), + new Star(TOKEN, subjectF), + new Star(TOKEN, subjectG), + new Star(TOKEN, subjectH), + new Star(TOKEN, subjectI), + new Star(TOKEN, subjectJ) + ) ); - - // when, then - assertThatThrownBy(() -> starService.addStarOnSubject(overCountSubject.getId(), TOKEN)) - .isInstanceOf(AllcllException.class) - .hasMessageContaining(String.format(AllcllErrorCode.STAR_LIMIT_EXCEEDED.getMessage(), MAX_STAR_NUMBER)); } @Test @@ -92,4 +111,76 @@ void alreadyExistStarSubject() { .isInstanceOf(AllcllException.class) .hasMessageContaining(expectExceptionMessage); } + + @Test + @DisplayName("즐겨찾기의 삭제를 검증한다.") + void deletePin() { + // given + Subject subject = createSubject("컴퓨터구조", "003278", "001", "김보예"); + subjectRepository.save(subject); + starRepository.save(new Star(TOKEN, subject)); + + // when + starService.deleteStarOnSubject(subject.getId(), TOKEN); + + // then + assertThat(starRepository.findAllByToken(TOKEN)).hasSize(0); + } + + @Test + @DisplayName("등록되지 않은 즐겨찾기의 삭제에 대한 예외를 검증한다.") + void deleteNotExistPin() { + // given + Subject starSubject = createSubject("즐겨찾기 된 과목", "123456", "001", "김보예"); + Subject notStarSubject = createSubject("즐겨찾기 안된 과목", "654321", "001", "김주환"); + subjectRepository.saveAll(List.of(starSubject, notStarSubject)); + starRepository.save(new Star(TOKEN, starSubject)); + + // when, then + assertThatThrownBy(() -> starService.deleteStarOnSubject(notStarSubject.getId(), TOKEN)) + .isInstanceOf(AllcllException.class) + .hasMessageContaining(AllcllErrorCode.STAR_SUBJECT_MISMATCH.getMessage()); + } + + @Test + @DisplayName("존재하지 않는 토큰에 대한 예외를 검증한다.") + void deleteNotExistToken() { + // given + Subject subject = createSubject("컴퓨터구조", "003278", "001", "김보예"); + subjectRepository.save(subject); + + // when, then + assertThatThrownBy(() -> starService.deleteStarOnSubject(subject.getId(), TOKEN)) + .isInstanceOf(AllcllException.class) + .hasMessageContaining(AllcllErrorCode.STAR_SUBJECT_MISMATCH.getMessage()); + } + + @Test + @DisplayName("등록된 핀이 존재할 때 조회 기능을 테스트한다.") + void retrieveExistPins() { + // given + int expectedSize = 1; + Subject subject = createSubject("컴퓨터구조", "003278", "001", "김보예"); + subjectRepository.save(subject); + starRepository.save(new Star(TOKEN, subject)); + + // when + SubjectIdsResponse response = starService.retrieveStars(TOKEN); + + // then + assertThat(response.subjects()).hasSize(expectedSize); + } + + @Test + @DisplayName("등록된 핀이 존재할 때 예외가 발생하지 않음을 검증한다.") + void retrieveStars() { + // given + int expectedSize = 0; + + // when + SubjectIdsResponse response = starService.retrieveStars(TOKEN); + + // then + assertThat(response.subjects()).hasSize(expectedSize); + } } From 3d5cbef2f6fd54a10184145460f055b88c5fa532 Mon Sep 17 00:00:00 2001 From: Sumin Date: Sat, 8 Feb 2025 00:18:12 +0900 Subject: [PATCH 08/18] =?UTF-8?q?refactor:=20Star=20=EC=97=94=ED=8B=B0?= =?UTF-8?q?=ED=8B=B0=EC=9D=98=20token=20=ED=95=84=EB=93=9C=EC=97=90=20null?= =?UTF-8?q?able=20=EC=98=B5=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/kr/allcll/seatfinder/star/Star.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/kr/allcll/seatfinder/star/Star.java b/src/main/java/kr/allcll/seatfinder/star/Star.java index 5720717..a7cc40f 100644 --- a/src/main/java/kr/allcll/seatfinder/star/Star.java +++ b/src/main/java/kr/allcll/seatfinder/star/Star.java @@ -23,7 +23,7 @@ public class Star { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(name = "token") + @Column(name = "token", nullable = false) private String token; @ManyToOne(fetch = FetchType.LAZY, optional = false) From fbd0f1f1333c8c7e47bdd5dba9838296926d88ff Mon Sep 17 00:00:00 2001 From: Sumin Date: Sat, 8 Feb 2025 00:18:40 +0900 Subject: [PATCH 09/18] =?UTF-8?q?refactor:=20=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EA=B8=B0=EB=B0=98=20=EC=A6=90=EA=B2=A8=EC=B0=BE=EA=B8=B0=20?= =?UTF-8?q?=EC=88=AB=EC=9E=90=20=EA=B2=80=EC=A6=9D=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/kr/allcll/seatfinder/star/StarRepository.java | 2 ++ src/main/java/kr/allcll/seatfinder/star/StarService.java | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/kr/allcll/seatfinder/star/StarRepository.java b/src/main/java/kr/allcll/seatfinder/star/StarRepository.java index 5049bf9..473af73 100644 --- a/src/main/java/kr/allcll/seatfinder/star/StarRepository.java +++ b/src/main/java/kr/allcll/seatfinder/star/StarRepository.java @@ -12,4 +12,6 @@ public interface StarRepository extends JpaRepository { List findAllByToken(String token); Optional findBySubjectAndToken(Subject subject, String token); + + Long countAllByToken(String token); } diff --git a/src/main/java/kr/allcll/seatfinder/star/StarService.java b/src/main/java/kr/allcll/seatfinder/star/StarService.java index ae6dd6d..742be67 100644 --- a/src/main/java/kr/allcll/seatfinder/star/StarService.java +++ b/src/main/java/kr/allcll/seatfinder/star/StarService.java @@ -23,15 +23,15 @@ public class StarService { @Transactional public void addStarOnSubject(Long subjectId, String token) { - List starsByToken = starRepository.findAllByToken(token); + Long starCount = starRepository.countAllByToken(token); Subject subject = subjectRepository.findById(subjectId) .orElseThrow(() -> new AllcllException(AllcllErrorCode.SUBJECT_NOT_FOUND)); - validateCanAddStar(starsByToken, subject, token); + validateCanAddStar(starCount, subject, token); starRepository.save(new Star(token, subject)); } - private void validateCanAddStar(List userStars, Subject subject, String token) { - if (userStars.size() >= MAX_STAR_NUMBER) { + private void validateCanAddStar(Long starCount, Subject subject, String token) { + if (starCount >= MAX_STAR_NUMBER) { throw new AllcllException(AllcllErrorCode.STAR_LIMIT_EXCEEDED, MAX_STAR_NUMBER); } if (starRepository.existsBySubjectAndToken(subject, token)) { From afe73d9383dd841dedcae24c18cd18864d4fe380 Mon Sep 17 00:00:00 2001 From: Sumin Date: Sat, 8 Feb 2025 00:18:52 +0900 Subject: [PATCH 10/18] =?UTF-8?q?refactor:=20=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EA=B8=B0=EB=B0=98=20=ED=95=80=20=EB=93=B1=EB=A1=9D=20=EC=88=AB?= =?UTF-8?q?=EC=9E=90=20=EA=B2=80=EC=A6=9D=20=EB=A1=9C=EC=A7=81=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/kr/allcll/seatfinder/pin/PinRepository.java | 2 ++ src/main/java/kr/allcll/seatfinder/pin/PinService.java | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/kr/allcll/seatfinder/pin/PinRepository.java b/src/main/java/kr/allcll/seatfinder/pin/PinRepository.java index 7d266f3..21812dc 100644 --- a/src/main/java/kr/allcll/seatfinder/pin/PinRepository.java +++ b/src/main/java/kr/allcll/seatfinder/pin/PinRepository.java @@ -12,4 +12,6 @@ public interface PinRepository extends JpaRepository { Optional findBySubjectAndToken(Subject subject, String token); boolean existsBySubjectAndToken(Subject subject, String token); + + Long countAllByToken(String token); } diff --git a/src/main/java/kr/allcll/seatfinder/pin/PinService.java b/src/main/java/kr/allcll/seatfinder/pin/PinService.java index b7ceebd..abd276e 100644 --- a/src/main/java/kr/allcll/seatfinder/pin/PinService.java +++ b/src/main/java/kr/allcll/seatfinder/pin/PinService.java @@ -23,15 +23,15 @@ public class PinService { @Transactional public void addPinOnSubject(Long subjectId, String token) { - List userPins = pinRepository.findAllByToken(token); + Long pinCount = pinRepository.countAllByToken(token); Subject subject = subjectRepository.findById(subjectId) .orElseThrow(() -> new AllcllException(AllcllErrorCode.SUBJECT_NOT_FOUND)); - validateCanAddPin(userPins, subject, token); + validateCanAddPin(pinCount, subject, token); pinRepository.save(new Pin(token, subject)); } - private void validateCanAddPin(List userPins, Subject subject, String token) { - if (userPins.size() >= MAX_PIN_NUMBER) { + private void validateCanAddPin(Long pinCount, Subject subject, String token) { + if (pinCount >= MAX_PIN_NUMBER) { throw new AllcllException(AllcllErrorCode.PIN_LIMIT_EXCEEDED, MAX_PIN_NUMBER); } if (pinRepository.existsBySubjectAndToken(subject, token)) { From c30e84469a9bbbedebe05e7da58d25766dfe33c8 Mon Sep 17 00:00:00 2001 From: Sumin Date: Sat, 8 Feb 2025 00:19:10 +0900 Subject: [PATCH 11/18] =?UTF-8?q?refactor:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EB=A6=AC=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../seatfinder/star/StarServiceTest.java | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java b/src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java index 16bc6a0..06ff24b 100644 --- a/src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java +++ b/src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java @@ -42,19 +42,37 @@ void setUp() { @DisplayName("즐겨찾기 5개 미만일 경우 정상 등록을 검증한다.") void addStarOnProject() { // given + int expected = 5; Subject subjectA = createSubject("컴퓨터구조", "003278", "001", "김보예"); - subjectRepository.save(subjectA); - starService.addStarOnSubject(subjectA.getId(), TOKEN); + Subject subjectB = createSubject("컴퓨터구조", "003278", "002", "김보예"); + Subject subjectC = createSubject("컴퓨터구조", "003278", "003", "김보예"); + Subject subjectD = createSubject("컴퓨터구조", "003278", "004", "김보예"); + Subject starSubject = createSubject("컴퓨터구조", "003278", "005", "김보예"); + subjectRepository.saveAll(List.of( + subjectA, + subjectB, + subjectC, + subjectD, + starSubject + )); + starRepository.saveAll(List.of( + new Star(TOKEN, subjectA), + new Star(TOKEN, subjectB), + new Star(TOKEN, subjectC), + new Star(TOKEN, subjectD) + ) + ); + starService.addStarOnSubject(starSubject.getId(), TOKEN); // when List result = starRepository.findAllByToken(TOKEN); // then - assertThat(result).hasSize(1); + assertThat(result).hasSize(expected); } @Test - @DisplayName("즐겨찾기가 5개 이상일 경우 예외를 검증한다.") + @DisplayName("즐겨찾기가 10개 이상일 경우 예외를 검증한다.") void canNotAddStarOnSubject() { // given Subject overCountSubject = createSubject("컴퓨터구조", "003278", "005", "김수민"); From 243bb0fad78873b211b536dbee9a836aca16067e Mon Sep 17 00:00:00 2001 From: Sumin Date: Sat, 8 Feb 2025 01:04:34 +0900 Subject: [PATCH 12/18] =?UTF-8?q?refactor:=20=ED=85=8C=EC=9D=B4=EB=B8=94?= =?UTF-8?q?=20=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/kr/allcll/seatfinder/pin/Pin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/kr/allcll/seatfinder/pin/Pin.java b/src/main/java/kr/allcll/seatfinder/pin/Pin.java index 6ae7bb7..3ca424d 100644 --- a/src/main/java/kr/allcll/seatfinder/pin/Pin.java +++ b/src/main/java/kr/allcll/seatfinder/pin/Pin.java @@ -15,7 +15,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; -@Table(name = "PIN") +@Table(name = "pins") @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) From 8d9693bc7df9c6e8d369e9a4965a99b73f930311 Mon Sep 17 00:00:00 2001 From: Sumin Date: Sat, 8 Feb 2025 02:20:20 +0900 Subject: [PATCH 13/18] =?UTF-8?q?test:=20Star=20Api=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../allcll/seatfinder/star/StarApiTest.java | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 src/test/java/kr/allcll/seatfinder/star/StarApiTest.java diff --git a/src/test/java/kr/allcll/seatfinder/star/StarApiTest.java b/src/test/java/kr/allcll/seatfinder/star/StarApiTest.java new file mode 100644 index 0000000..7ceb2c1 --- /dev/null +++ b/src/test/java/kr/allcll/seatfinder/star/StarApiTest.java @@ -0,0 +1,78 @@ +package kr.allcll.seatfinder.star; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import jakarta.servlet.http.Cookie; +import java.util.List; +import kr.allcll.seatfinder.pin.dto.SubjectIdResponse; +import kr.allcll.seatfinder.pin.dto.SubjectIdsResponse; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.test.context.bean.override.mockito.MockitoBean; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; + +@WebMvcTest(StarApi.class) +class StarApiTest { + + @Autowired + private MockMvc mockMvc; + + @MockitoBean + private StarService starService; + + @Test + @DisplayName("관담 기능의 즐겨찾기 등록을 할 때에 요청과 응답을 확인한다.") + void addStarOnSubjectWhenStarNotExist() throws Exception { + // when, then + mockMvc.perform(post("/api/stars") + .param("subjectId", "1")) + .andExpect(status().isOk()); + } + + @Test + @DisplayName("관담 기능의 즐겨찾기를 삭제할 때 요청과 응답을 확인한다.") + void deleteStarOnSubject() throws Exception { + // when, then + mockMvc.perform(delete("/api/stars/{subjectId}", 1L)) + .andExpect(status().isOk()); + } + + @Test + @DisplayName("관담기능을 조회할 때 요청과 응답을 확인한다.") + void retrieveStars() throws Exception { + // given + String expected = """ + { + "subjects":[ + { + "subjectId":1 + }, + { + "subjectId":2 + } + ] + } + """; + + List subjects = List.of(new SubjectIdResponse(1L), new SubjectIdResponse(2L)); + when(starService.retrieveStars("tokenValue")) + .thenReturn(new SubjectIdsResponse(subjects)); + + // when + MvcResult result = mockMvc.perform(get("/api/stars") + .cookie(new Cookie("token", "tokenValue"))) + .andExpect(status().isOk()) + .andReturn(); + + // then + assertThat(result.getResponse().getContentAsString()).isEqualToIgnoringWhitespace(expected); + } +} From 1dc19d87ad69237d25b52e6c53d753985c796ae6 Mon Sep 17 00:00:00 2001 From: Sumin Date: Sat, 8 Feb 2025 13:08:48 +0900 Subject: [PATCH 14/18] =?UTF-8?q?refactor:=20=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kr/allcll/seatfinder/pin/PinService.java | 6 ++--- .../kr/allcll/seatfinder/star/StarApi.java | 6 ++--- .../seatfinder/star/StarRepository.java | 5 ++-- .../allcll/seatfinder/star/StarService.java | 23 +++++++++---------- .../star/dto/StarredSubjectIdResponse.java | 7 ++++++ .../star/dto/StarredSubjectIdsResponse.java | 9 ++++++++ .../allcll/seatfinder/star/StarApiTest.java | 11 +++++---- .../seatfinder/star/StarServiceTest.java | 13 +++++------ 8 files changed, 48 insertions(+), 32 deletions(-) create mode 100644 src/main/java/kr/allcll/seatfinder/star/dto/StarredSubjectIdResponse.java create mode 100644 src/main/java/kr/allcll/seatfinder/star/dto/StarredSubjectIdsResponse.java diff --git a/src/main/java/kr/allcll/seatfinder/pin/PinService.java b/src/main/java/kr/allcll/seatfinder/pin/PinService.java index abd276e..5b0ca50 100644 --- a/src/main/java/kr/allcll/seatfinder/pin/PinService.java +++ b/src/main/java/kr/allcll/seatfinder/pin/PinService.java @@ -23,14 +23,14 @@ public class PinService { @Transactional public void addPinOnSubject(Long subjectId, String token) { - Long pinCount = pinRepository.countAllByToken(token); Subject subject = subjectRepository.findById(subjectId) .orElseThrow(() -> new AllcllException(AllcllErrorCode.SUBJECT_NOT_FOUND)); - validateCanAddPin(pinCount, subject, token); + validateCanAddPin(subject, token); pinRepository.save(new Pin(token, subject)); } - private void validateCanAddPin(Long pinCount, Subject subject, String token) { + private void validateCanAddPin(Subject subject, String token) { + Long pinCount = pinRepository.countAllByToken(token); if (pinCount >= MAX_PIN_NUMBER) { throw new AllcllException(AllcllErrorCode.PIN_LIMIT_EXCEEDED, MAX_PIN_NUMBER); } diff --git a/src/main/java/kr/allcll/seatfinder/star/StarApi.java b/src/main/java/kr/allcll/seatfinder/star/StarApi.java index 0d2dc65..0bb573b 100644 --- a/src/main/java/kr/allcll/seatfinder/star/StarApi.java +++ b/src/main/java/kr/allcll/seatfinder/star/StarApi.java @@ -1,7 +1,7 @@ package kr.allcll.seatfinder.star; import kr.allcll.seatfinder.ThreadLocalHolder; -import kr.allcll.seatfinder.pin.dto.SubjectIdsResponse; +import kr.allcll.seatfinder.star.dto.StarredSubjectIdsResponse; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; @@ -30,8 +30,8 @@ public ResponseEntity deleteStarOnSubject(@PathVariable Long subjectId) { } @GetMapping("/api/stars") - public ResponseEntity retrieveStars() { - SubjectIdsResponse response = starService.retrieveStars(ThreadLocalHolder.SHARED_TOKEN.get()); + public ResponseEntity retrieveStars() { + StarredSubjectIdsResponse response = starService.retrieveStars(ThreadLocalHolder.SHARED_TOKEN.get()); return ResponseEntity.ok(response); } } diff --git a/src/main/java/kr/allcll/seatfinder/star/StarRepository.java b/src/main/java/kr/allcll/seatfinder/star/StarRepository.java index 473af73..1c12351 100644 --- a/src/main/java/kr/allcll/seatfinder/star/StarRepository.java +++ b/src/main/java/kr/allcll/seatfinder/star/StarRepository.java @@ -1,7 +1,6 @@ package kr.allcll.seatfinder.star; import java.util.List; -import java.util.Optional; import kr.allcll.seatfinder.subject.Subject; import org.springframework.data.jpa.repository.JpaRepository; @@ -11,7 +10,7 @@ public interface StarRepository extends JpaRepository { List findAllByToken(String token); - Optional findBySubjectAndToken(Subject subject, String token); - Long countAllByToken(String token); + + void deleteStarBySubjectAndToken(Subject subject, String token); } diff --git a/src/main/java/kr/allcll/seatfinder/star/StarService.java b/src/main/java/kr/allcll/seatfinder/star/StarService.java index 742be67..577a878 100644 --- a/src/main/java/kr/allcll/seatfinder/star/StarService.java +++ b/src/main/java/kr/allcll/seatfinder/star/StarService.java @@ -3,8 +3,8 @@ import java.util.List; import kr.allcll.seatfinder.exception.AllcllErrorCode; import kr.allcll.seatfinder.exception.AllcllException; -import kr.allcll.seatfinder.pin.dto.SubjectIdResponse; -import kr.allcll.seatfinder.pin.dto.SubjectIdsResponse; +import kr.allcll.seatfinder.star.dto.StarredSubjectIdResponse; +import kr.allcll.seatfinder.star.dto.StarredSubjectIdsResponse; import kr.allcll.seatfinder.subject.Subject; import kr.allcll.seatfinder.subject.SubjectRepository; import lombok.RequiredArgsConstructor; @@ -16,21 +16,22 @@ @RequiredArgsConstructor public class StarService { - private static final int MAX_STAR_NUMBER = 10; + private static final int MAX_STAR_NUMBER = 50; private final StarRepository starRepository; private final SubjectRepository subjectRepository; @Transactional public void addStarOnSubject(Long subjectId, String token) { - Long starCount = starRepository.countAllByToken(token); + Subject subject = subjectRepository.findById(subjectId) .orElseThrow(() -> new AllcllException(AllcllErrorCode.SUBJECT_NOT_FOUND)); - validateCanAddStar(starCount, subject, token); + validateCanAddStar(subject, token); starRepository.save(new Star(token, subject)); } - private void validateCanAddStar(Long starCount, Subject subject, String token) { + private void validateCanAddStar(Subject subject, String token) { + Long starCount = starRepository.countAllByToken(token); if (starCount >= MAX_STAR_NUMBER) { throw new AllcllException(AllcllErrorCode.STAR_LIMIT_EXCEEDED, MAX_STAR_NUMBER); } @@ -43,15 +44,13 @@ private void validateCanAddStar(Long starCount, Subject subject, String token) { public void deleteStarOnSubject(Long subjectId, String token) { Subject subject = subjectRepository.findById(subjectId) .orElseThrow(() -> new AllcllException(AllcllErrorCode.SUBJECT_NOT_FOUND)); - Star star = starRepository.findBySubjectAndToken(subject, token) - .orElseThrow(() -> new AllcllException(AllcllErrorCode.STAR_SUBJECT_MISMATCH)); - starRepository.deleteById(star.getId()); + starRepository.deleteStarBySubjectAndToken(subject, token); } - public SubjectIdsResponse retrieveStars(String token) { + public StarredSubjectIdsResponse retrieveStars(String token) { List stars = starRepository.findAllByToken(token); - return new SubjectIdsResponse(stars.stream() - .map(star -> new SubjectIdResponse(star.getSubject().getId())) + return new StarredSubjectIdsResponse(stars.stream() + .map(star -> new StarredSubjectIdResponse(star.getSubject().getId())) .toList()); } } diff --git a/src/main/java/kr/allcll/seatfinder/star/dto/StarredSubjectIdResponse.java b/src/main/java/kr/allcll/seatfinder/star/dto/StarredSubjectIdResponse.java new file mode 100644 index 0000000..56d5d3c --- /dev/null +++ b/src/main/java/kr/allcll/seatfinder/star/dto/StarredSubjectIdResponse.java @@ -0,0 +1,7 @@ +package kr.allcll.seatfinder.star.dto; + +public record StarredSubjectIdResponse( + Long subjectId +) { + +} diff --git a/src/main/java/kr/allcll/seatfinder/star/dto/StarredSubjectIdsResponse.java b/src/main/java/kr/allcll/seatfinder/star/dto/StarredSubjectIdsResponse.java new file mode 100644 index 0000000..b0bc48b --- /dev/null +++ b/src/main/java/kr/allcll/seatfinder/star/dto/StarredSubjectIdsResponse.java @@ -0,0 +1,9 @@ +package kr.allcll.seatfinder.star.dto; + +import java.util.List; + +public record StarredSubjectIdsResponse( + List subjects +) { + +} diff --git a/src/test/java/kr/allcll/seatfinder/star/StarApiTest.java b/src/test/java/kr/allcll/seatfinder/star/StarApiTest.java index 7ceb2c1..53cf617 100644 --- a/src/test/java/kr/allcll/seatfinder/star/StarApiTest.java +++ b/src/test/java/kr/allcll/seatfinder/star/StarApiTest.java @@ -9,8 +9,8 @@ import jakarta.servlet.http.Cookie; import java.util.List; -import kr.allcll.seatfinder.pin.dto.SubjectIdResponse; -import kr.allcll.seatfinder.pin.dto.SubjectIdsResponse; +import kr.allcll.seatfinder.star.dto.StarredSubjectIdResponse; +import kr.allcll.seatfinder.star.dto.StarredSubjectIdsResponse; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -62,9 +62,12 @@ void retrieveStars() throws Exception { } """; - List subjects = List.of(new SubjectIdResponse(1L), new SubjectIdResponse(2L)); + List subjects = List.of( + new StarredSubjectIdResponse(1L), + new StarredSubjectIdResponse(2L) + ); when(starService.retrieveStars("tokenValue")) - .thenReturn(new SubjectIdsResponse(subjects)); + .thenReturn(new StarredSubjectIdsResponse(subjects)); // when MvcResult result = mockMvc.perform(get("/api/stars") diff --git a/src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java b/src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java index 06ff24b..89c08a8 100644 --- a/src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java +++ b/src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java @@ -7,7 +7,7 @@ import java.util.List; import kr.allcll.seatfinder.exception.AllcllErrorCode; import kr.allcll.seatfinder.exception.AllcllException; -import kr.allcll.seatfinder.pin.dto.SubjectIdsResponse; +import kr.allcll.seatfinder.star.dto.StarredSubjectIdsResponse; import kr.allcll.seatfinder.subject.Subject; import kr.allcll.seatfinder.subject.SubjectRepository; import org.junit.jupiter.api.BeforeEach; @@ -20,7 +20,6 @@ @SpringBootTest(webEnvironment = WebEnvironment.NONE) class StarServiceTest { - private static final int MAX_STAR_NUMBER = 10; private static final String TOKEN = "token"; @Autowired @@ -75,6 +74,7 @@ void addStarOnProject() { @DisplayName("즐겨찾기가 10개 이상일 경우 예외를 검증한다.") void canNotAddStarOnSubject() { // given + int MAX_STAR_NUMBER = 10; Subject overCountSubject = createSubject("컴퓨터구조", "003278", "005", "김수민"); subjectRepository.save(overCountSubject); saveSubjectsAndTenStars(); @@ -122,12 +122,11 @@ void alreadyExistStarSubject() { Subject subject = createSubject("컴퓨터구조", "003278", "001", "김보예"); subjectRepository.save(subject); starRepository.save(new Star(TOKEN, subject)); - String expectExceptionMessage = new AllcllException(AllcllErrorCode.DUPLICATE_STAR, "컴퓨터구조").getMessage(); // when, then assertThatThrownBy(() -> starService.addStarOnSubject(subject.getId(), TOKEN)) .isInstanceOf(AllcllException.class) - .hasMessageContaining(expectExceptionMessage); + .hasMessageContaining(new AllcllException(AllcllErrorCode.DUPLICATE_STAR, "컴퓨터구조").getMessage()); } @Test @@ -146,7 +145,7 @@ void deletePin() { } @Test - @DisplayName("등록되지 않은 즐겨찾기의 삭제에 대한 예외를 검증한다.") + @DisplayName("등록되지 않은 즐겨찾기를 삭제하면 예외가 발생한다.") void deleteNotExistPin() { // given Subject starSubject = createSubject("즐겨찾기 된 과목", "123456", "001", "김보예"); @@ -183,7 +182,7 @@ void retrieveExistPins() { starRepository.save(new Star(TOKEN, subject)); // when - SubjectIdsResponse response = starService.retrieveStars(TOKEN); + StarredSubjectIdsResponse response = starService.retrieveStars(TOKEN); // then assertThat(response.subjects()).hasSize(expectedSize); @@ -196,7 +195,7 @@ void retrieveStars() { int expectedSize = 0; // when - SubjectIdsResponse response = starService.retrieveStars(TOKEN); + StarredSubjectIdsResponse response = starService.retrieveStars(TOKEN); // then assertThat(response.subjects()).hasSize(expectedSize); From 4a0c2970524462dd39697058a616c45021cf6e7e Mon Sep 17 00:00:00 2001 From: Sumin Date: Sat, 8 Feb 2025 13:34:25 +0900 Subject: [PATCH 15/18] =?UTF-8?q?refactor:=20=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EB=B0=98=EC=98=81=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../seatfinder/star/StarRepository.java | 2 +- .../allcll/seatfinder/star/StarService.java | 4 +- .../seatfinder/star/StarServiceTest.java | 77 +++++++------------ 3 files changed, 31 insertions(+), 52 deletions(-) diff --git a/src/main/java/kr/allcll/seatfinder/star/StarRepository.java b/src/main/java/kr/allcll/seatfinder/star/StarRepository.java index 1c12351..b53bcf4 100644 --- a/src/main/java/kr/allcll/seatfinder/star/StarRepository.java +++ b/src/main/java/kr/allcll/seatfinder/star/StarRepository.java @@ -12,5 +12,5 @@ public interface StarRepository extends JpaRepository { Long countAllByToken(String token); - void deleteStarBySubjectAndToken(Subject subject, String token); + void deleteStarBySubjectIdAndToken(Long subjectId, String token); } diff --git a/src/main/java/kr/allcll/seatfinder/star/StarService.java b/src/main/java/kr/allcll/seatfinder/star/StarService.java index 577a878..bc27078 100644 --- a/src/main/java/kr/allcll/seatfinder/star/StarService.java +++ b/src/main/java/kr/allcll/seatfinder/star/StarService.java @@ -42,9 +42,7 @@ private void validateCanAddStar(Subject subject, String token) { @Transactional public void deleteStarOnSubject(Long subjectId, String token) { - Subject subject = subjectRepository.findById(subjectId) - .orElseThrow(() -> new AllcllException(AllcllErrorCode.SUBJECT_NOT_FOUND)); - starRepository.deleteStarBySubjectAndToken(subject, token); + starRepository.deleteStarBySubjectIdAndToken(subjectId, token); } public StarredSubjectIdsResponse retrieveStars(String token) { diff --git a/src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java b/src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java index 89c08a8..91b0a0c 100644 --- a/src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java +++ b/src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java @@ -2,6 +2,7 @@ import static kr.allcll.seatfinder.support.fixture.SubjectFixture.createSubject; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.util.List; @@ -74,7 +75,7 @@ void addStarOnProject() { @DisplayName("즐겨찾기가 10개 이상일 경우 예외를 검증한다.") void canNotAddStarOnSubject() { // given - int MAX_STAR_NUMBER = 10; + int MAX_STAR_NUMBER = 50; Subject overCountSubject = createSubject("컴퓨터구조", "003278", "005", "김수민"); subjectRepository.save(overCountSubject); saveSubjectsAndTenStars(); @@ -86,33 +87,12 @@ void canNotAddStarOnSubject() { } private void saveSubjectsAndTenStars() { - Subject subjectA = createSubject("컴퓨터구조", "003278", "001", "김보예"); - Subject subjectB = createSubject("운영체제", "003279", "001", "김수민"); - Subject subjectC = createSubject("자료구조", "003280", "001", "김봉케"); - Subject subjectD = createSubject("알고리즘", "003281", "001", "오현지"); - Subject subjectE = createSubject("컴퓨터구조", "003278", "002", "전유채"); - Subject subjectF = createSubject("과목6", "003279", "003", "전유채"); - Subject subjectG = createSubject("과목7", "003270", "002", "김주환"); - Subject subjectH = createSubject("운영체제", "113278", "001", "김뽀예"); - Subject subjectI = createSubject("컴퓨터구조", "003278", "002", "전유채"); - Subject subjectJ = createSubject("자료구조", "003272", "001", "박희준"); - subjectRepository.saveAll( - List.of(subjectA, subjectB, subjectC, subjectD, subjectE, subjectF, - subjectG, subjectH, subjectI, subjectJ)); - starRepository.saveAll( - List.of( - new Star(TOKEN, subjectA), - new Star(TOKEN, subjectB), - new Star(TOKEN, subjectC), - new Star(TOKEN, subjectD), - new Star(TOKEN, subjectE), - new Star(TOKEN, subjectF), - new Star(TOKEN, subjectG), - new Star(TOKEN, subjectH), - new Star(TOKEN, subjectI), - new Star(TOKEN, subjectJ) - ) - ); + for (int i = 0; i < 50; i++) { + Subject subject = createSubject("컴퓨터구조", "003278", "001", "김보예"); + subjectRepository.save(subject); + Star star = new Star(TOKEN, subject); + starRepository.save(star); + } } @Test @@ -131,7 +111,7 @@ void alreadyExistStarSubject() { @Test @DisplayName("즐겨찾기의 삭제를 검증한다.") - void deletePin() { + void deleteStar() { // given Subject subject = createSubject("컴퓨터구조", "003278", "001", "김보예"); subjectRepository.save(subject); @@ -145,36 +125,37 @@ void deletePin() { } @Test - @DisplayName("등록되지 않은 즐겨찾기를 삭제하면 예외가 발생한다.") - void deleteNotExistPin() { + @DisplayName("즐겨찾기 되지 않은 않는 과목의 즐겨찾기를 삭제할 때에도 예외가 발생하지 않음을 검증한다.") + void deleteStarNotExistSubject() { // given - Subject starSubject = createSubject("즐겨찾기 된 과목", "123456", "001", "김보예"); - Subject notStarSubject = createSubject("즐겨찾기 안된 과목", "654321", "001", "김주환"); - subjectRepository.saveAll(List.of(starSubject, notStarSubject)); - starRepository.save(new Star(TOKEN, starSubject)); + Subject subjectA = createSubject("컴구", "001234", "001", "김보예"); + Subject notStarredSubject = createSubject("컴네", "004321", "001", "김수민"); + subjectRepository.saveAll(List.of(subjectA, notStarredSubject)); + starRepository.save(new Star(TOKEN, subjectA)); // when, then - assertThatThrownBy(() -> starService.deleteStarOnSubject(notStarSubject.getId(), TOKEN)) - .isInstanceOf(AllcllException.class) - .hasMessageContaining(AllcllErrorCode.STAR_SUBJECT_MISMATCH.getMessage()); + assertThatCode(() -> { + starService.deleteStarOnSubject(notStarredSubject.getId(), TOKEN); + }).doesNotThrowAnyException(); } @Test - @DisplayName("존재하지 않는 토큰에 대한 예외를 검증한다.") - void deleteNotExistToken() { + @DisplayName("존재 하지 않는 토큰의 즐겨찾기를 삭제할 때에도 예외가 발생하지 않음을 검증한다.") + void deleteStarNotExistToken() { // given - Subject subject = createSubject("컴퓨터구조", "003278", "001", "김보예"); - subjectRepository.save(subject); + Subject subjectA = createSubject("컴구", "001234", "001", "김보예"); + subjectRepository.save(subjectA); + starRepository.save(new Star(TOKEN, subjectA)); // when, then - assertThatThrownBy(() -> starService.deleteStarOnSubject(subject.getId(), TOKEN)) - .isInstanceOf(AllcllException.class) - .hasMessageContaining(AllcllErrorCode.STAR_SUBJECT_MISMATCH.getMessage()); + assertThatCode(() -> { + starService.deleteStarOnSubject(subjectA.getId(), "notExistToken"); + }).doesNotThrowAnyException(); } @Test - @DisplayName("등록된 핀이 존재할 때 조회 기능을 테스트한다.") - void retrieveExistPins() { + @DisplayName("등록된 즐겨찾기가 존재할 때 조회 기능을 테스트한다.") + void retrieveExisStars() { // given int expectedSize = 1; Subject subject = createSubject("컴퓨터구조", "003278", "001", "김보예"); @@ -189,7 +170,7 @@ void retrieveExistPins() { } @Test - @DisplayName("등록된 핀이 존재할 때 예외가 발생하지 않음을 검증한다.") + @DisplayName("등록된 즐겨찾기가 존재할 때 예외가 발생하지 않음을 검증한다.") void retrieveStars() { // given int expectedSize = 0; From 1461ca1b49639f87c11a57f2e2f1b09031fccbe9 Mon Sep 17 00:00:00 2001 From: Sumin Date: Sat, 8 Feb 2025 13:38:33 +0900 Subject: [PATCH 16/18] =?UTF-8?q?refactor:=20SubjectService=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=EC=97=90=20StarRepository=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kr/allcll/seatfinder/subject/SubjectServiceTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/test/java/kr/allcll/seatfinder/subject/SubjectServiceTest.java b/src/test/java/kr/allcll/seatfinder/subject/SubjectServiceTest.java index 20ac03e..5937813 100644 --- a/src/test/java/kr/allcll/seatfinder/subject/SubjectServiceTest.java +++ b/src/test/java/kr/allcll/seatfinder/subject/SubjectServiceTest.java @@ -5,6 +5,7 @@ import static org.assertj.core.api.Assertions.tuple; import java.util.List; +import kr.allcll.seatfinder.star.StarRepository; import kr.allcll.seatfinder.subject.dto.SubjectResponse; import kr.allcll.seatfinder.subject.dto.SubjectsResponse; import org.junit.jupiter.api.BeforeEach; @@ -23,8 +24,12 @@ class SubjectServiceTest { @Autowired private SubjectRepository subjectRepository; + @Autowired + private StarRepository starRepository; + @BeforeEach void setUp() { + starRepository.deleteAllInBatch(); subjectRepository.deleteAllInBatch(); initializeSubjects(); } From 0e586cedc94e35510347793c5b0e6827d1de3b90 Mon Sep 17 00:00:00 2001 From: Sumin Date: Sat, 8 Feb 2025 13:46:31 +0900 Subject: [PATCH 17/18] =?UTF-8?q?refactor:=20Star=20=EC=97=94=ED=8B=B0?= =?UTF-8?q?=ED=8B=B0=20=ED=85=8C=EC=9D=B4=EB=B8=94=20=EB=AA=85=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/kr/allcll/seatfinder/star/Star.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/kr/allcll/seatfinder/star/Star.java b/src/main/java/kr/allcll/seatfinder/star/Star.java index a7cc40f..47005fe 100644 --- a/src/main/java/kr/allcll/seatfinder/star/Star.java +++ b/src/main/java/kr/allcll/seatfinder/star/Star.java @@ -13,7 +13,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; -@Table(name = "star") +@Table(name = "stars") @Entity @Getter @NoArgsConstructor From 3c3dec7df9441ff5256c70dc919d745c723d6f49 Mon Sep 17 00:00:00 2001 From: Sumin Date: Sat, 8 Feb 2025 13:49:42 +0900 Subject: [PATCH 18/18] =?UTF-8?q?refactor:=20=EC=A0=95=EC=B1=85=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=EC=97=90=20=EB=94=B0=EB=A5=B8=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../seatfinder/star/StarServiceTest.java | 39 ++++++++----------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java b/src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java index 91b0a0c..676dfb8 100644 --- a/src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java +++ b/src/test/java/kr/allcll/seatfinder/star/StarServiceTest.java @@ -39,29 +39,13 @@ void setUp() { } @Test - @DisplayName("즐겨찾기 5개 미만일 경우 정상 등록을 검증한다.") + @DisplayName("즐겨찾기 50개 미만일 경우 정상 등록을 검증한다.") void addStarOnProject() { // given - int expected = 5; - Subject subjectA = createSubject("컴퓨터구조", "003278", "001", "김보예"); - Subject subjectB = createSubject("컴퓨터구조", "003278", "002", "김보예"); - Subject subjectC = createSubject("컴퓨터구조", "003278", "003", "김보예"); - Subject subjectD = createSubject("컴퓨터구조", "003278", "004", "김보예"); + int expected = 50; Subject starSubject = createSubject("컴퓨터구조", "003278", "005", "김보예"); - subjectRepository.saveAll(List.of( - subjectA, - subjectB, - subjectC, - subjectD, - starSubject - )); - starRepository.saveAll(List.of( - new Star(TOKEN, subjectA), - new Star(TOKEN, subjectB), - new Star(TOKEN, subjectC), - new Star(TOKEN, subjectD) - ) - ); + saveSubjectsAndStars(); + subjectRepository.save(starSubject); starService.addStarOnSubject(starSubject.getId(), TOKEN); // when @@ -71,14 +55,23 @@ void addStarOnProject() { assertThat(result).hasSize(expected); } + private void saveSubjectsAndStars() { + for (int i = 0; i < 49; i++) { + Subject subject = createSubject("컴퓨터구조", "003278", "001", "김보예"); + subjectRepository.save(subject); + Star star = new Star(TOKEN, subject); + starRepository.save(star); + } + } + @Test - @DisplayName("즐겨찾기가 10개 이상일 경우 예외를 검증한다.") + @DisplayName("즐겨찾기가 50개 이상일 경우 예외를 검증한다.") void canNotAddStarOnSubject() { // given int MAX_STAR_NUMBER = 50; Subject overCountSubject = createSubject("컴퓨터구조", "003278", "005", "김수민"); subjectRepository.save(overCountSubject); - saveSubjectsAndTenStars(); + saveSubjectsAndMaxStars(); // when, then assertThatThrownBy(() -> starService.addStarOnSubject(overCountSubject.getId(), TOKEN)) @@ -86,7 +79,7 @@ void canNotAddStarOnSubject() { .hasMessageContaining(String.format(AllcllErrorCode.STAR_LIMIT_EXCEEDED.getMessage(), MAX_STAR_NUMBER)); } - private void saveSubjectsAndTenStars() { + private void saveSubjectsAndMaxStars() { for (int i = 0; i < 50; i++) { Subject subject = createSubject("컴퓨터구조", "003278", "001", "김보예"); subjectRepository.save(subject);