From 7836559b774813bb8351dcb6246bef79242db679 Mon Sep 17 00:00:00 2001 From: highjune Date: Sun, 28 May 2023 22:29:01 +0900 Subject: [PATCH 01/27] =?UTF-8?q?refactor(domain):=20step1=20=ED=94=BC?= =?UTF-8?q?=EB=93=9C=EB=B0=B1=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Answer에서 setter 메서드 제거 - Answer에서 toString() 함수 제일 밑으로 이동 --- src/main/java/nextstep/qna/domain/Answers.java | 5 ++++- src/main/java/nextstep/qna/domain/Question.java | 16 ++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/main/java/nextstep/qna/domain/Answers.java b/src/main/java/nextstep/qna/domain/Answers.java index 5485ebc0e3..eb94d768d5 100644 --- a/src/main/java/nextstep/qna/domain/Answers.java +++ b/src/main/java/nextstep/qna/domain/Answers.java @@ -6,7 +6,6 @@ import java.util.Objects; public class Answers implements Iterable { - private final List answers; public Answers() { @@ -24,6 +23,10 @@ public List getAnswers() { return this.answers; } + public void deleteAnswers() { + answers.stream() + .forEach(answer -> answer.delete()); + } @Override public Iterator iterator() { return answers.iterator(); diff --git a/src/main/java/nextstep/qna/domain/Question.java b/src/main/java/nextstep/qna/domain/Question.java index 51d98e8d5a..38923971b5 100644 --- a/src/main/java/nextstep/qna/domain/Question.java +++ b/src/main/java/nextstep/qna/domain/Question.java @@ -41,10 +41,6 @@ public void addAnswer(Answer answer) { answers.add(answer); } - private void setDeleted(boolean deleted) { - this.deleted = deleted; - } - public boolean isDeleted() { return deleted; } @@ -53,14 +49,9 @@ public List getAnswers() { return answers.getAnswers(); } - @Override - public String toString() { - return "Question [id=" + getId() + ", title=" + title + ", contents=" + contents + ", writer=" + writer + "]"; - } - public DeleteHistories delete(NsUser loginUser) { isSameUser(loginUser); - this.setDeleted(true); + this.deleted = true; return documentedDeleteHistories(); } @@ -78,4 +69,9 @@ private DeleteHistories documentedDeleteHistories() { .forEach(answer -> deleteHistories.add(answer.delete())); return deleteHistories; } + + @Override + public String toString() { + return "Question [id=" + getId() + ", title=" + title + ", contents=" + contents + ", writer=" + writer + "]"; + } } From 49789fb35522933b021ca120fd1bdf2ea7c4538d Mon Sep 17 00:00:00 2001 From: highjune Date: Sun, 28 May 2023 22:46:55 +0900 Subject: [PATCH 02/27] =?UTF-8?q?refactor(domain):=20setter=EC=82=AD?= =?UTF-8?q?=EC=A0=9C,=20Answers=EC=97=90=20delete()=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/nextstep/qna/domain/Answer.java | 2 +- src/main/java/nextstep/qna/domain/Answers.java | 5 +++-- src/main/java/nextstep/qna/domain/Question.java | 15 +++++---------- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/main/java/nextstep/qna/domain/Answer.java b/src/main/java/nextstep/qna/domain/Answer.java index f6fff30f8d..a956d080ce 100644 --- a/src/main/java/nextstep/qna/domain/Answer.java +++ b/src/main/java/nextstep/qna/domain/Answer.java @@ -71,7 +71,7 @@ public String toString() { public DeleteHistory delete() { isSameUser(); - this.setDeleted(true); + this.deleted = true; return DeleteHistory.createAnswer(this.id, this.writer); } diff --git a/src/main/java/nextstep/qna/domain/Answers.java b/src/main/java/nextstep/qna/domain/Answers.java index eb94d768d5..2c52409a66 100644 --- a/src/main/java/nextstep/qna/domain/Answers.java +++ b/src/main/java/nextstep/qna/domain/Answers.java @@ -23,9 +23,10 @@ public List getAnswers() { return this.answers; } - public void deleteAnswers() { + public DeleteHistories delete(DeleteHistories deleteHistories) { answers.stream() - .forEach(answer -> answer.delete()); + .forEach(answer -> deleteHistories.add(answer.delete())); + return deleteHistories; } @Override public Iterator iterator() { diff --git a/src/main/java/nextstep/qna/domain/Question.java b/src/main/java/nextstep/qna/domain/Question.java index 38923971b5..8522560b97 100644 --- a/src/main/java/nextstep/qna/domain/Question.java +++ b/src/main/java/nextstep/qna/domain/Question.java @@ -52,7 +52,11 @@ public List getAnswers() { public DeleteHistories delete(NsUser loginUser) { isSameUser(loginUser); this.deleted = true; - return documentedDeleteHistories(); + + DeleteHistories deleteHistories = new DeleteHistories(); + deleteHistories.add(DeleteHistory.createQuestion(this.id, this.writer)); + + return answers.delete(deleteHistories); } private void isSameUser(NsUser loginUser) { @@ -61,15 +65,6 @@ private void isSameUser(NsUser loginUser) { } } - private DeleteHistories documentedDeleteHistories() { - DeleteHistories deleteHistories = new DeleteHistories(); - deleteHistories.add(DeleteHistory.createQuestion(this.id, this.writer)); - - answers.getAnswers().stream() - .forEach(answer -> deleteHistories.add(answer.delete())); - return deleteHistories; - } - @Override public String toString() { return "Question [id=" + getId() + ", title=" + title + ", contents=" + contents + ", writer=" + writer + "]"; From b4b0382742c31105303b22892b1197f09b824eb6 Mon Sep 17 00:00:00 2001 From: highjune Date: Sun, 28 May 2023 23:28:48 +0900 Subject: [PATCH 03/27] =?UTF-8?q?refactor(domain):=20DeleteHistory?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EC=A0=95=EC=A0=81=20=ED=8C=A9=ED=86=A0?= =?UTF-8?q?=EB=A6=AC=20=EB=A9=94=EC=84=9C=EB=93=9C=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/nextstep/qna/domain/Answer.java | 26 ++----------------- .../nextstep/qna/domain/DeleteHistory.java | 8 +++--- .../java/nextstep/qna/domain/Question.java | 2 +- .../qna/domain/DeleteHistoriesTest.java | 6 ++--- 4 files changed, 10 insertions(+), 32 deletions(-) diff --git a/src/main/java/nextstep/qna/domain/Answer.java b/src/main/java/nextstep/qna/domain/Answer.java index a956d080ce..e188d1fa80 100644 --- a/src/main/java/nextstep/qna/domain/Answer.java +++ b/src/main/java/nextstep/qna/domain/Answer.java @@ -72,7 +72,7 @@ public String toString() { public DeleteHistory delete() { isSameUser(); this.deleted = true; - return DeleteHistory.createAnswer(this.id, this.writer); + return DeleteHistory.createAnswer(this); } private void isSameUser() { @@ -80,26 +80,4 @@ private void isSameUser() { throw new CannotDeleteException("다른 사람이 쓴 답변이 있어 삭제할 수 없습니다."); } } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Answer answer = (Answer) o; - return isDeleted() == answer.isDeleted() - && Objects.equals(getId(), answer.getId()) - && Objects.equals(getWriter(), answer.getWriter()) - && Objects.equals(question, answer.question) - && Objects.equals(getContents(), answer.getContents()) - && Objects.equals(createdDate, answer.createdDate); - } - - @Override - public int hashCode() { - return Objects.hash(getId(), getWriter(), question, getContents(), isDeleted(), createdDate); - } -} +} \ No newline at end of file diff --git a/src/main/java/nextstep/qna/domain/DeleteHistory.java b/src/main/java/nextstep/qna/domain/DeleteHistory.java index fb58b97e57..f6e28f215f 100644 --- a/src/main/java/nextstep/qna/domain/DeleteHistory.java +++ b/src/main/java/nextstep/qna/domain/DeleteHistory.java @@ -29,12 +29,12 @@ public DeleteHistory(ContentType contentType, Long contentId, NsUser deletedBy) this.deletedBy = deletedBy; } - public static DeleteHistory createAnswer(Long id, NsUser writer) { - return new DeleteHistory(ContentType.ANSWER, id, writer); + public static DeleteHistory createAnswer(Answer answer) { + return new DeleteHistory(ContentType.ANSWER, answer.getId(), answer.getWriter()); } - public static DeleteHistory createQuestion(Long id, NsUser writer) { - return new DeleteHistory(ContentType.QUESTION, id, writer); + public static DeleteHistory createQuestion(Question question) { + return new DeleteHistory(ContentType.QUESTION, question.getId(), question.getWriter()); } @Override diff --git a/src/main/java/nextstep/qna/domain/Question.java b/src/main/java/nextstep/qna/domain/Question.java index 8522560b97..7ddcce5aa3 100644 --- a/src/main/java/nextstep/qna/domain/Question.java +++ b/src/main/java/nextstep/qna/domain/Question.java @@ -54,7 +54,7 @@ public DeleteHistories delete(NsUser loginUser) { this.deleted = true; DeleteHistories deleteHistories = new DeleteHistories(); - deleteHistories.add(DeleteHistory.createQuestion(this.id, this.writer)); + deleteHistories.add(DeleteHistory.createQuestion(this)); return answers.delete(deleteHistories); } diff --git a/src/test/java/nextstep/qna/domain/DeleteHistoriesTest.java b/src/test/java/nextstep/qna/domain/DeleteHistoriesTest.java index cbacaaa894..4ec15c617d 100644 --- a/src/test/java/nextstep/qna/domain/DeleteHistoriesTest.java +++ b/src/test/java/nextstep/qna/domain/DeleteHistoriesTest.java @@ -26,7 +26,7 @@ void setUp() { @DisplayName("Question을 추가했을 경우 Question에 대한 DeleteHistory를 만들어 리스트에 추가한다.") @Test void addQuestion_CreateDeleteHistory_And_AddDeleteHistorylist() { - deleteHistories.add(DeleteHistory.createQuestion(Q1.getId(), Q1.getWriter())); + deleteHistories.add(DeleteHistory.createQuestion(Q1)); DeleteHistory deleteHistoryQ1 = new DeleteHistory(ContentType.QUESTION, Q1.getId(), Q1.getWriter()); @@ -38,8 +38,8 @@ void addQuestion_CreateDeleteHistory_And_AddDeleteHistorylist() { @DisplayName("Answer를 추가했을 경우 Answer에 대한 DeleteHistory를 만들어 리스트에 추가한다.") @Test void addAnswer_CreateDeleteHistory_And_AddDeleteHistorylist() { - deleteHistories.add(DeleteHistory.createAnswer(A1.getId(), A1.getWriter())); - deleteHistories.add(DeleteHistory.createAnswer(A2.getId(), A2.getWriter())); + deleteHistories.add(DeleteHistory.createAnswer(A1)); + deleteHistories.add(DeleteHistory.createAnswer(A2)); DeleteHistory deleteHistoryA1 = new DeleteHistory(ContentType.ANSWER, A1.getId(), A1.getWriter()); DeleteHistory deleteHistoryA2 = new DeleteHistory(ContentType.ANSWER, A2.getId(), A2.getWriter()); From 3d688c5749e11106f2bf8056a9b7b98a06ef4ee6 Mon Sep 17 00:00:00 2001 From: highjune Date: Mon, 29 May 2023 00:21:20 +0900 Subject: [PATCH 04/27] =?UTF-8?q?docs(README.md):=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=EC=9A=94=EA=B5=AC=EC=82=AC=ED=95=AD=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/README.md b/README.md index 069f3af51c..c98b501e5a 100644 --- a/README.md +++ b/README.md @@ -30,3 +30,32 @@ - [x] question를 add 하면 question에 대한 DeleteHistory 를 만들어 리스트에 추가한다. - [x] answer을 add 하면 question에 대한 DeleteHistory를 만들어 리스트에 추가한다. + +## 수강신청 2단계(도메인 설계) 기능 목록 +### Student(학생) +- [ ] 학생은 수강신청을 할 수 있다. +- [ ] 수강 신청시 강의(Session)의 현재 수강 인원이 1 증가된다. +- [ ] 수강신청시 최대 인원을 넘게 되면 예외를 던진다. +- [ ] 수강 신청은 강의(Session) 의 상태가 `모집중` 일 때만 가능하다. + - [ ] `모집중`이 아닐 경우 예외를 던진다. + +### Course(과정) +- [ ] 강의를 과정에 추가하고, 기수에 따라 강의를 조회할 수 있다. +- [ ] 기수가 유효하지 않다면 (음수 or 초과 기수 조회) 예외를 던진다. + +### Session(강의) +- [ ] 시작일과 종료일을 가진다. +- [ ] 강의 커버 이미지 정보를 가진다. +- type(타입) + - [ ] 무료, 유료 강의 2가지 값을 가진다(enum) +- status(상태) + - [ ] 준비중, 모집중, 3가지를 가진다(enum) + +### 수강 신청 기능 요구사항 +- 과정(Course)은 기수 단위로 여러 개의 강의(Session)를 가질 수 있다. +- 강의는 시작일과 종료일을 가진다. +- 강의는 강의 커버 이미지 정보를 가진다. +- 강의는 무료 강의와 유료 강의로 나뉜다. +- 강의 상태는 준비중, 모집중, 종료 3가지 상태를 가진다. +- 강의 수강신청은 강의 상태가 모집중일 때만 가능하다. +- 강의는 강의 최대 수강 인원을 초과할 수 없다. \ No newline at end of file From b39de98b9fcc76d5aaa060b09a4c8a523a5e5472 Mon Sep 17 00:00:00 2001 From: highjune Date: Mon, 29 May 2023 00:34:30 +0900 Subject: [PATCH 05/27] =?UTF-8?q?test(domain):=20SessionTimeLineTest=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=84=A0=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../courses/domain/SessionTimeLineTest.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/test/java/nextstep/courses/domain/SessionTimeLineTest.java diff --git a/src/test/java/nextstep/courses/domain/SessionTimeLineTest.java b/src/test/java/nextstep/courses/domain/SessionTimeLineTest.java new file mode 100644 index 0000000000..046ee4c538 --- /dev/null +++ b/src/test/java/nextstep/courses/domain/SessionTimeLineTest.java @@ -0,0 +1,30 @@ +package nextstep.courses.domain; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.time.LocalDateTime; + +public class SessionTimeLineTest { + + @Test + @DisplayName("강의 시작일이 강의 종료일보다 빠르면 예외를 던지지 않는다.") + void create_CreateAtBeforeThanClosedAt_NoException() { + LocalDateTime createAt = LocalDateTime.now(); + LocalDateTime closeAt = createAt.plusDays(5); + + Assertions.assertThatNoException() + .isThrownBy(() -> new SessionTimeLine(createAt, closeAt)); + } + + @Test + @DisplayName("강의 시작일이 강의 종료일보다 느리면 예외를 던진다.") + void create_CreateAtBeforeThanClosedAt_NoException() { + LocalDateTime createAt = LocalDateTime.now(); + LocalDateTime closeAt = createAt.minusDays(5); + + Assertions.assertThatNoException() + .isThrownBy(() -> new SessionTimeLine(createAt, closeAt)); + } +} From 9c735e64860c51fe2a8656d03c8692dc6df16c9b Mon Sep 17 00:00:00 2001 From: highjune Date: Mon, 29 May 2023 00:45:01 +0900 Subject: [PATCH 06/27] =?UTF-8?q?feat(domain):=20SessionTimeLine=20?= =?UTF-8?q?=EA=B0=9D=EC=B2=B4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../courses/domain/SessionTimeLine.java | 21 +++++++++++++++++++ .../courses/domain/SessionTimeLineTest.java | 4 ++-- 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 src/main/java/nextstep/courses/domain/SessionTimeLine.java diff --git a/src/main/java/nextstep/courses/domain/SessionTimeLine.java b/src/main/java/nextstep/courses/domain/SessionTimeLine.java new file mode 100644 index 0000000000..95a5c976e4 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/SessionTimeLine.java @@ -0,0 +1,21 @@ +package nextstep.courses.domain; + +import java.time.LocalDateTime; + +public class SessionTimeLine { + + private LocalDateTime createAt; + private LocalDateTime closeAt; + + public SessionTimeLine(LocalDateTime createAt, LocalDateTime closeAt) { + validateInterval(createAt, closeAt); + this.createAt = createAt; + this.closeAt = closeAt; + } + + private void validateInterval(LocalDateTime createAt, LocalDateTime closeAt) { + if (closeAt.isBefore(createAt)) { + throw new IllegalArgumentException("강의 마감일이 시작일보다 빠를 수 없습니다."); + } + } +} diff --git a/src/test/java/nextstep/courses/domain/SessionTimeLineTest.java b/src/test/java/nextstep/courses/domain/SessionTimeLineTest.java index 046ee4c538..3e9e4dbe0e 100644 --- a/src/test/java/nextstep/courses/domain/SessionTimeLineTest.java +++ b/src/test/java/nextstep/courses/domain/SessionTimeLineTest.java @@ -20,11 +20,11 @@ void create_CreateAtBeforeThanClosedAt_NoException() { @Test @DisplayName("강의 시작일이 강의 종료일보다 느리면 예외를 던진다.") - void create_CreateAtBeforeThanClosedAt_NoException() { + void create_CreateAtAfterThanClosedAt_NoException() { LocalDateTime createAt = LocalDateTime.now(); LocalDateTime closeAt = createAt.minusDays(5); - Assertions.assertThatNoException() + Assertions.assertThatIllegalArgumentException() .isThrownBy(() -> new SessionTimeLine(createAt, closeAt)); } } From 3d8a518e7e95e777874fbe11bce4215c24eaa087 Mon Sep 17 00:00:00 2001 From: highjune Date: Mon, 29 May 2023 00:49:16 +0900 Subject: [PATCH 07/27] =?UTF-8?q?refactor(domain):=20SessionTimeLine=20?= =?UTF-8?q?=EB=82=A0=EC=A7=9C=20=EB=A1=9C=EC=A7=81=20=EC=B2=B4=ED=81=AC=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 --- src/main/java/nextstep/courses/domain/SessionTimeLine.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/nextstep/courses/domain/SessionTimeLine.java b/src/main/java/nextstep/courses/domain/SessionTimeLine.java index 95a5c976e4..bc4c785af5 100644 --- a/src/main/java/nextstep/courses/domain/SessionTimeLine.java +++ b/src/main/java/nextstep/courses/domain/SessionTimeLine.java @@ -14,8 +14,8 @@ public SessionTimeLine(LocalDateTime createAt, LocalDateTime closeAt) { } private void validateInterval(LocalDateTime createAt, LocalDateTime closeAt) { - if (closeAt.isBefore(createAt)) { - throw new IllegalArgumentException("강의 마감일이 시작일보다 빠를 수 없습니다."); + if (createAt.isAfter(closeAt)) { + throw new IllegalArgumentException("강의 시작일과 마감일을 잘못 입력하였습니다."); } } } From 45b2955162409094ab6ebf2b91610df4bf8ca089 Mon Sep 17 00:00:00 2001 From: highjune Date: Mon, 29 May 2023 01:14:55 +0900 Subject: [PATCH 08/27] =?UTF-8?q?feat(domain):=20SessionStatus=20Enum=20?= =?UTF-8?q?=EA=B0=9D=EC=B2=B4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- .../courses/domain/SessionStatus.java | 20 +++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 src/main/java/nextstep/courses/domain/SessionStatus.java diff --git a/README.md b/README.md index c98b501e5a..dea083b920 100644 --- a/README.md +++ b/README.md @@ -44,12 +44,12 @@ - [ ] 기수가 유효하지 않다면 (음수 or 초과 기수 조회) 예외를 던진다. ### Session(강의) -- [ ] 시작일과 종료일을 가진다. +- [x] 시작일과 종료일을 가진다. - [ ] 강의 커버 이미지 정보를 가진다. - type(타입) - [ ] 무료, 유료 강의 2가지 값을 가진다(enum) - status(상태) - - [ ] 준비중, 모집중, 3가지를 가진다(enum) + - [ ] 준비중, 모집중, 종료 3가지를 가진다(enum) ### 수강 신청 기능 요구사항 - 과정(Course)은 기수 단위로 여러 개의 강의(Session)를 가질 수 있다. diff --git a/src/main/java/nextstep/courses/domain/SessionStatus.java b/src/main/java/nextstep/courses/domain/SessionStatus.java new file mode 100644 index 0000000000..4b1fe92109 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/SessionStatus.java @@ -0,0 +1,20 @@ +package nextstep.courses.domain; + +public enum SessionStatus { + + READY("준비중"), + OPENED("모집중"), + CLSOED("종료") + ; + + private String name; + + SessionStatus(String name) { + this.name = name; + } + + public boolean canJoin() { + return this.equals(OPENED); + } + +} From 2e32239b235e9fa3747c1ecf595a5290174e166c Mon Sep 17 00:00:00 2001 From: highjune Date: Mon, 29 May 2023 01:16:59 +0900 Subject: [PATCH 09/27] =?UTF-8?q?feat(domain):=20SessionType=20enum=20?= =?UTF-8?q?=EA=B0=9D=EC=B2=B4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- .../java/nextstep/courses/domain/SessionType.java | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 src/main/java/nextstep/courses/domain/SessionType.java diff --git a/README.md b/README.md index dea083b920..e7b48cc26b 100644 --- a/README.md +++ b/README.md @@ -47,9 +47,9 @@ - [x] 시작일과 종료일을 가진다. - [ ] 강의 커버 이미지 정보를 가진다. - type(타입) - - [ ] 무료, 유료 강의 2가지 값을 가진다(enum) + - [x] 무료, 유료 강의 2가지 값을 가진다(enum) - status(상태) - - [ ] 준비중, 모집중, 종료 3가지를 가진다(enum) + - [x] 준비중, 모집중, 종료 3가지를 가진다(enum) ### 수강 신청 기능 요구사항 - 과정(Course)은 기수 단위로 여러 개의 강의(Session)를 가질 수 있다. diff --git a/src/main/java/nextstep/courses/domain/SessionType.java b/src/main/java/nextstep/courses/domain/SessionType.java new file mode 100644 index 0000000000..b1aa2216bc --- /dev/null +++ b/src/main/java/nextstep/courses/domain/SessionType.java @@ -0,0 +1,13 @@ +package nextstep.courses.domain; + +public enum SessionType { + + FREE("무료"), + CHANGED("유료") + ; + + private String name; + SessionType(String name) { + this.name = name; + } +} From 4e64f85651b1884fb12559fe0ab889d69e7a4f0b Mon Sep 17 00:00:00 2001 From: highjune Date: Mon, 29 May 2023 01:22:03 +0900 Subject: [PATCH 10/27] =?UTF-8?q?feat(domain):=20SessionInfo=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nextstep/courses/domain/SessionInfo.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/main/java/nextstep/courses/domain/SessionInfo.java diff --git a/src/main/java/nextstep/courses/domain/SessionInfo.java b/src/main/java/nextstep/courses/domain/SessionInfo.java new file mode 100644 index 0000000000..12f1ed1fd7 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/SessionInfo.java @@ -0,0 +1,18 @@ +package nextstep.courses.domain; + +public class SessionInfo { + + private final Long courseId; + private final Long ownerId; + private final String title; + private final String coverImageInfo; + private final SessionType sessionType; + + public SessionInfo(Long courseId, Long ownerId, String title, String coverImageInfo, SessionType sessionType) { + this.courseId = courseId; + this.ownerId = ownerId; + this.title = title; + this.coverImageInfo = coverImageInfo; + this.sessionType = sessionType; + } +} \ No newline at end of file From 08ac6b972291ed11bc6088d73dc9971fb465f158 Mon Sep 17 00:00:00 2001 From: highjune Date: Mon, 29 May 2023 01:32:27 +0900 Subject: [PATCH 11/27] =?UTF-8?q?feat(domain):=20Session=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/nextstep/courses/domain/Session.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/main/java/nextstep/courses/domain/Session.java diff --git a/src/main/java/nextstep/courses/domain/Session.java b/src/main/java/nextstep/courses/domain/Session.java new file mode 100644 index 0000000000..ae0b165537 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/Session.java @@ -0,0 +1,32 @@ +package nextstep.courses.domain; + +import java.time.LocalDateTime; + +public class Session { + + + private final SessionInfo sessionInfo; + private final SessionStatus sessionStatus; + private final SessionTimeLine sessionTimeLine; + // Set + private final Long maxNumberOfStudent; + + public Session(Long courseId, Long ownerId, String title, String coverImageInfo, + SessionType sessionType, SessionStatus sessionStatus, + LocalDateTime createdAt, LocalDateTime closedAt, Long maxNumOfStudent) { + + this(new SessionInfo(courseId, ownerId, title, coverImageInfo, sessionType), + sessionStatus, + new SessionTimeLine(createdAt, closedAt), + maxNumOfStudent + ); + } + + public Session(SessionInfo sessionInfo, SessionStatus sessionStatus, + SessionTimeLine sessionTimeLine, Long maxNumberOfStudent){ + this.sessionInfo = sessionInfo; + this.sessionStatus = sessionStatus; + this.sessionTimeLine = sessionTimeLine; + this.maxNumberOfStudent = maxNumberOfStudent; + } +} From b516e7b94199573036a44ca55b1b8a0c5085966c Mon Sep 17 00:00:00 2001 From: highjune Date: Mon, 29 May 2023 01:51:41 +0900 Subject: [PATCH 12/27] =?UTF-8?q?feat(domain):=20Student=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=EA=B5=AC=ED=98=84=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Session에 Set 추가 - StudentTest 위한SessionCreator 추가 - Student 객체 구현 --- src/main/java/nextstep/courses/domain/Session.java | 4 +++- src/main/java/nextstep/courses/domain/Student.java | 12 ++++++++++++ .../nextstep/courses/domain/SessionCreator.java | 13 +++++++++++++ .../java/nextstep/courses/domain/StudentTest.java | 14 ++++++++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 src/main/java/nextstep/courses/domain/Student.java create mode 100644 src/test/java/nextstep/courses/domain/SessionCreator.java create mode 100644 src/test/java/nextstep/courses/domain/StudentTest.java diff --git a/src/main/java/nextstep/courses/domain/Session.java b/src/main/java/nextstep/courses/domain/Session.java index ae0b165537..c562193144 100644 --- a/src/main/java/nextstep/courses/domain/Session.java +++ b/src/main/java/nextstep/courses/domain/Session.java @@ -1,6 +1,8 @@ package nextstep.courses.domain; import java.time.LocalDateTime; +import java.util.HashSet; +import java.util.Set; public class Session { @@ -8,7 +10,7 @@ public class Session { private final SessionInfo sessionInfo; private final SessionStatus sessionStatus; private final SessionTimeLine sessionTimeLine; - // Set + private final Set students = new HashSet<>(); private final Long maxNumberOfStudent; public Session(Long courseId, Long ownerId, String title, String coverImageInfo, diff --git a/src/main/java/nextstep/courses/domain/Student.java b/src/main/java/nextstep/courses/domain/Student.java new file mode 100644 index 0000000000..6dc8e2874d --- /dev/null +++ b/src/main/java/nextstep/courses/domain/Student.java @@ -0,0 +1,12 @@ +package nextstep.courses.domain; + +public class Student { + + private final Long studentId; + private final Long sessionId; + + public Student(Long studentId, Long sessionId) { + this.studentId = studentId; + this.sessionId = sessionId; + } +} diff --git a/src/test/java/nextstep/courses/domain/SessionCreator.java b/src/test/java/nextstep/courses/domain/SessionCreator.java new file mode 100644 index 0000000000..c2a2f23259 --- /dev/null +++ b/src/test/java/nextstep/courses/domain/SessionCreator.java @@ -0,0 +1,13 @@ +package nextstep.courses.domain; + +import java.time.LocalDateTime; + +public class SessionCreator { + + public static Session create(Long maxNumberOfStudent, SessionStatus sessionStatus) { + SessionInfo sessionInfo = new SessionInfo(1L, 0L, "titleName", + "coverImage", SessionType.FREE); + SessionTimeLine sessionTimeLine = new SessionTimeLine(LocalDateTime.now(), LocalDateTime.now().plusDays(10)); + return new Session(sessionInfo, sessionStatus, sessionTimeLine, maxNumberOfStudent); + } +} diff --git a/src/test/java/nextstep/courses/domain/StudentTest.java b/src/test/java/nextstep/courses/domain/StudentTest.java new file mode 100644 index 0000000000..a876be5035 --- /dev/null +++ b/src/test/java/nextstep/courses/domain/StudentTest.java @@ -0,0 +1,14 @@ +package nextstep.courses.domain; + +import org.junit.jupiter.api.BeforeEach; + +public class StudentTest { + + @BeforeEach + void setUp() { + Student june1 = new Student(0L, 10L); + Student june2 = new Student(0L, 10L); + Student june3 = new Student(0L, 10L); + Session session = SessionCreator.create(2L, SessionStatus.OPENED); + } +} From 6a684ead5ab5eb9293357059b8fb4e337368b544 Mon Sep 17 00:00:00 2001 From: highjune Date: Mon, 29 May 2023 01:56:12 +0900 Subject: [PATCH 13/27] =?UTF-8?q?test(domain):=20StudentTest=20=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EB=93=B1=EB=A1=9D=EC=8B=9C=201=20=EC=A6=9D?= =?UTF-8?q?=EA=B0=80=ED=95=98=EB=8A=94=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EB=A8=BC=EC=A0=80=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nextstep/courses/domain/StudentTest.java | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/test/java/nextstep/courses/domain/StudentTest.java b/src/test/java/nextstep/courses/domain/StudentTest.java index a876be5035..3fc7f1c41a 100644 --- a/src/test/java/nextstep/courses/domain/StudentTest.java +++ b/src/test/java/nextstep/courses/domain/StudentTest.java @@ -1,14 +1,30 @@ package nextstep.courses.domain; +import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; public class StudentTest { + Student june1; + Student june2; + Student june3; + Session session; + @BeforeEach void setUp() { - Student june1 = new Student(0L, 10L); - Student june2 = new Student(0L, 10L); - Student june3 = new Student(0L, 10L); - Session session = SessionCreator.create(2L, SessionStatus.OPENED); + june1 = new Student(0L, 10L); + june2 = new Student(0L, 10L); + june3 = new Student(0L, 10L); + session = SessionCreator.create(2L, SessionStatus.OPENED); + } + + @Test + @DisplayName("학생은 수강신청시 강의의 현재 수강인원이 1이 증가한다.") + void enroll_SessionMaxNumberOfValue_PlusOne() { + june1.enroll(session); + Assertions.assertThat(session.totalStudentNum()).isEqualTo(1); } + } From 38cb914c952c896a14e22714ac8775e9906ebf56 Mon Sep 17 00:00:00 2001 From: highjune Date: Mon, 29 May 2023 02:01:05 +0900 Subject: [PATCH 14/27] =?UTF-8?q?feat(domain):=20Student=20=EB=A5=BC=20Ses?= =?UTF-8?q?sion=EC=97=90=20=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/nextstep/courses/domain/Session.java | 9 +++++++++ src/main/java/nextstep/courses/domain/Student.java | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/src/main/java/nextstep/courses/domain/Session.java b/src/main/java/nextstep/courses/domain/Session.java index c562193144..422d0ff452 100644 --- a/src/main/java/nextstep/courses/domain/Session.java +++ b/src/main/java/nextstep/courses/domain/Session.java @@ -31,4 +31,13 @@ public Session(SessionInfo sessionInfo, SessionStatus sessionStatus, this.sessionTimeLine = sessionTimeLine; this.maxNumberOfStudent = maxNumberOfStudent; } + + public void add(Student student) { + // todo - validate + this.students.add(student); + } + + public int totalStudentNum() { + return students.size(); + } } diff --git a/src/main/java/nextstep/courses/domain/Student.java b/src/main/java/nextstep/courses/domain/Student.java index 6dc8e2874d..bf2dfe6944 100644 --- a/src/main/java/nextstep/courses/domain/Student.java +++ b/src/main/java/nextstep/courses/domain/Student.java @@ -9,4 +9,8 @@ public Student(Long studentId, Long sessionId) { this.studentId = studentId; this.sessionId = sessionId; } + + public void enroll(Session session) { + session.add(this); + } } From 944cd30b1b1d9f467b6f802d1ff9fc78aa2c4844 Mon Sep 17 00:00:00 2001 From: highjune Date: Mon, 29 May 2023 02:08:23 +0900 Subject: [PATCH 15/27] =?UTF-8?q?feat(domain):=20=EC=88=98=EA=B0=95?= =?UTF-8?q?=EC=8B=A0=EC=B2=AD=EC=8B=9C=20=EC=9D=B8=EC=9B=90=20=EC=88=98=20?= =?UTF-8?q?=EC=B2=B4=ED=81=AC=20=EB=A1=9C=EC=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 테스트 추가 - Student에 로직 추가 --- .../courses/domain/CannotEnrollException.java | 8 ++++++++ .../java/nextstep/courses/domain/Session.java | 5 ++++- .../java/nextstep/courses/domain/StudentTest.java | 15 ++++++++++++++- 3 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 src/main/java/nextstep/courses/domain/CannotEnrollException.java diff --git a/src/main/java/nextstep/courses/domain/CannotEnrollException.java b/src/main/java/nextstep/courses/domain/CannotEnrollException.java new file mode 100644 index 0000000000..17d709db99 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/CannotEnrollException.java @@ -0,0 +1,8 @@ +package nextstep.courses.domain; + +public class CannotEnrollException extends RuntimeException{ + + public CannotEnrollException(String message) { + super(message); + } +} diff --git a/src/main/java/nextstep/courses/domain/Session.java b/src/main/java/nextstep/courses/domain/Session.java index 422d0ff452..cba5dadeca 100644 --- a/src/main/java/nextstep/courses/domain/Session.java +++ b/src/main/java/nextstep/courses/domain/Session.java @@ -33,7 +33,10 @@ public Session(SessionInfo sessionInfo, SessionStatus sessionStatus, } public void add(Student student) { - // todo - validate + if (totalStudentNum() == maxNumberOfStudent) { + throw new CannotEnrollException( + "현재 강의(Session)는 수강인원이 꽉 차서 더 이상 등록할 수 없습니다." + "최대인원 " + maxNumberOfStudent); + } this.students.add(student); } diff --git a/src/test/java/nextstep/courses/domain/StudentTest.java b/src/test/java/nextstep/courses/domain/StudentTest.java index 3fc7f1c41a..ce3280f210 100644 --- a/src/test/java/nextstep/courses/domain/StudentTest.java +++ b/src/test/java/nextstep/courses/domain/StudentTest.java @@ -5,6 +5,8 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.*; + public class StudentTest { Student june1; @@ -24,7 +26,18 @@ void setUp() { @DisplayName("학생은 수강신청시 강의의 현재 수강인원이 1이 증가한다.") void enroll_SessionMaxNumberOfValue_PlusOne() { june1.enroll(session); - Assertions.assertThat(session.totalStudentNum()).isEqualTo(1); + assertThat(session.totalStudentNum()).isEqualTo(1); + } + + @Test + @DisplayName("학생은 수강신청시 강의의 최대 수강신청 인원을 넘을 경우 예외를 던진다.") + void enroll_OutOfMaxNumberOfStudent_ThrowException() { + session.add(june1); + session.add(june2); + + assertThatThrownBy(() -> session.add(june3)) + .isInstanceOf(CannotEnrollException.class) + .hasMessageContaining("현재 강의(Session)는 수강인원이 꽉 차서 더 이상 등록할 수 없습니다."); } } From 25c83d2bb8fcecf70dc6c8b29bae09835342a4e7 Mon Sep 17 00:00:00 2001 From: highjune Date: Mon, 29 May 2023 02:12:12 +0900 Subject: [PATCH 16/27] =?UTF-8?q?test(domain):=20=EC=88=98=EA=B0=95?= =?UTF-8?q?=EC=8B=A0=EC=B2=AD=EC=8B=9C=20=EC=B5=9C=EB=8C=80=20=EC=88=98?= =?UTF-8?q?=EA=B0=95=EC=9D=B8=EC=9B=90=20=EC=9D=B4=ED=95=98=EB=A9=B4=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=20=EB=8D=98=EC=A7=80=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EB=8A=94=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 ++++---- .../java/nextstep/courses/domain/StudentTest.java | 12 +++++++++++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e7b48cc26b..0035d05b07 100644 --- a/README.md +++ b/README.md @@ -33,9 +33,9 @@ ## 수강신청 2단계(도메인 설계) 기능 목록 ### Student(학생) -- [ ] 학생은 수강신청을 할 수 있다. -- [ ] 수강 신청시 강의(Session)의 현재 수강 인원이 1 증가된다. -- [ ] 수강신청시 최대 인원을 넘게 되면 예외를 던진다. +- [x] 학생은 수강신청을 할 수 있다. +- [x] 수강 신청시 강의(Session)의 현재 수강 인원이 1 증가된다. +- [x] 수강신청시 최대 인원을 넘게 되면 예외를 던진다. - [ ] 수강 신청은 강의(Session) 의 상태가 `모집중` 일 때만 가능하다. - [ ] `모집중`이 아닐 경우 예외를 던진다. @@ -45,7 +45,7 @@ ### Session(강의) - [x] 시작일과 종료일을 가진다. -- [ ] 강의 커버 이미지 정보를 가진다. +- [x] 강의 커버 이미지 정보를 가진다. - type(타입) - [x] 무료, 유료 강의 2가지 값을 가진다(enum) - status(상태) diff --git a/src/test/java/nextstep/courses/domain/StudentTest.java b/src/test/java/nextstep/courses/domain/StudentTest.java index ce3280f210..d2f6518a50 100644 --- a/src/test/java/nextstep/courses/domain/StudentTest.java +++ b/src/test/java/nextstep/courses/domain/StudentTest.java @@ -30,7 +30,7 @@ void enroll_SessionMaxNumberOfValue_PlusOne() { } @Test - @DisplayName("학생은 수강신청시 강의의 최대 수강신청 인원을 넘을 경우 예외를 던진다.") + @DisplayName("수강신청시 최대 수강신청 인원을 넘을 경우 예외를 던진다.") void enroll_OutOfMaxNumberOfStudent_ThrowException() { session.add(june1); session.add(june2); @@ -40,4 +40,14 @@ void enroll_OutOfMaxNumberOfStudent_ThrowException() { .hasMessageContaining("현재 강의(Session)는 수강인원이 꽉 차서 더 이상 등록할 수 없습니다."); } + @Test + @DisplayName("수강신청시 최대 수강인원을 넘지 않을 경우 예외를 던지지 않는다.") + void enroll_LessThanMaxNumberOfStudent_NoException() { + Session session = SessionCreator.create(5L, SessionStatus.READY); + + assertThatNoException().isThrownBy(() -> session.add(june1)); + assertThatNoException().isThrownBy(() -> session.add(june2)); + assertThatNoException().isThrownBy(() -> session.add(june3)); + } + } From 2f7a50230fa4881357bcf21e6598b4b604abb544 Mon Sep 17 00:00:00 2001 From: highjune Date: Mon, 29 May 2023 02:23:16 +0900 Subject: [PATCH 17/27] =?UTF-8?q?test(domain):=20StudentTest=20=EA=B0=95?= =?UTF-8?q?=EC=9D=98=20=EC=83=81=ED=83=9C=EC=97=90=20=EB=94=B0=EB=A5=B8=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 --- .../java/nextstep/courses/domain/Session.java | 4 +++ .../nextstep/courses/domain/StudentTest.java | 30 ++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/main/java/nextstep/courses/domain/Session.java b/src/main/java/nextstep/courses/domain/Session.java index cba5dadeca..c0c8710b2b 100644 --- a/src/main/java/nextstep/courses/domain/Session.java +++ b/src/main/java/nextstep/courses/domain/Session.java @@ -33,6 +33,10 @@ public Session(SessionInfo sessionInfo, SessionStatus sessionStatus, } public void add(Student student) { + if (!sessionStatus.canJoin()) { + throw new CannotEnrollException("현재는 수강신청을 할 수 없는 강의 상태입니다. 현재 강의 상태 = " + sessionStatus.name()); + } + if (totalStudentNum() == maxNumberOfStudent) { throw new CannotEnrollException( "현재 강의(Session)는 수강인원이 꽉 차서 더 이상 등록할 수 없습니다." + "최대인원 " + maxNumberOfStudent); diff --git a/src/test/java/nextstep/courses/domain/StudentTest.java b/src/test/java/nextstep/courses/domain/StudentTest.java index d2f6518a50..5f1e06a38b 100644 --- a/src/test/java/nextstep/courses/domain/StudentTest.java +++ b/src/test/java/nextstep/courses/domain/StudentTest.java @@ -43,11 +43,39 @@ void enroll_OutOfMaxNumberOfStudent_ThrowException() { @Test @DisplayName("수강신청시 최대 수강인원을 넘지 않을 경우 예외를 던지지 않는다.") void enroll_LessThanMaxNumberOfStudent_NoException() { - Session session = SessionCreator.create(5L, SessionStatus.READY); + Session session = SessionCreator.create(3L, SessionStatus.OPENED); assertThatNoException().isThrownBy(() -> session.add(june1)); assertThatNoException().isThrownBy(() -> session.add(june2)); assertThatNoException().isThrownBy(() -> session.add(june3)); } + @Test + @DisplayName("강의 상태(SessionStatus) '모집중'일 경우에 수강신청이 가능하다(예외를 던지지 않는다.") + void enroll_SessionStatus_OPENED_NoException() { + Session session = SessionCreator.create(3L, SessionStatus.OPENED); + + assertThatNoException().isThrownBy(() -> session.add(june1)); + } + + @Test + @DisplayName("강의 상태(SessionStatus) '준비중'일 경우에 수깅신청시 예외를 던진다.") + void enroll_SessionStatus_READY_ThrowException() { + Session session = SessionCreator.create(3L, SessionStatus.READY); + + assertThatThrownBy(() -> session.add(june1)) + .isInstanceOf(CannotEnrollException.class); + + } + + @Test + @DisplayName("강의 상태(SessionStatus) '종료'일 경우에 수깅신청시 예외를 던진다.") + void enroll_SessionStatus_CLOSED_ThrowException() { + Session session = SessionCreator.create(3L, SessionStatus.CLSOED); + + assertThatThrownBy(() -> session.add(june1)) + .isInstanceOf(CannotEnrollException.class); + } + + } From 0312ae04369c9e748f769f44523254a7ec9bfbe6 Mon Sep 17 00:00:00 2001 From: highjune Date: Mon, 29 May 2023 02:27:57 +0900 Subject: [PATCH 18/27] =?UTF-8?q?feat(domain):=20StudentRepository=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/nextstep/courses/domain/Session.java | 8 ++++++-- .../nextstep/courses/domain/StudentRepository.java | 10 ++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 src/main/java/nextstep/courses/domain/StudentRepository.java diff --git a/src/main/java/nextstep/courses/domain/Session.java b/src/main/java/nextstep/courses/domain/Session.java index c0c8710b2b..66cf95c04e 100644 --- a/src/main/java/nextstep/courses/domain/Session.java +++ b/src/main/java/nextstep/courses/domain/Session.java @@ -37,9 +37,9 @@ public void add(Student student) { throw new CannotEnrollException("현재는 수강신청을 할 수 없는 강의 상태입니다. 현재 강의 상태 = " + sessionStatus.name()); } - if (totalStudentNum() == maxNumberOfStudent) { + if (isPositionFull()) { throw new CannotEnrollException( - "현재 강의(Session)는 수강인원이 꽉 차서 더 이상 등록할 수 없습니다." + "최대인원 " + maxNumberOfStudent); + "현재 강의(Session)는 수강인원이 꽉 차서 더 이상 등록할 수 없습니다." + "최대인원 = " + maxNumberOfStudent); } this.students.add(student); } @@ -47,4 +47,8 @@ public void add(Student student) { public int totalStudentNum() { return students.size(); } + + private boolean isPositionFull() { + return totalStudentNum() == maxNumberOfStudent; + } } diff --git a/src/main/java/nextstep/courses/domain/StudentRepository.java b/src/main/java/nextstep/courses/domain/StudentRepository.java new file mode 100644 index 0000000000..4e82e98a99 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/StudentRepository.java @@ -0,0 +1,10 @@ +package nextstep.courses.domain; + +import java.util.List; + +public interface StudentRepository { + + int save(Student student); + + List findBySessionId(Long sessionId); +} From 9787ed51e6d3bfa35376f041e5222d857162889e Mon Sep 17 00:00:00 2001 From: highjune Date: Mon, 29 May 2023 02:59:55 +0900 Subject: [PATCH 19/27] =?UTF-8?q?test(domain):=20=EA=B8=B0=EC=88=98?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EA=B0=95=EC=9D=98=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20&=20=ED=94=84?= =?UTF-8?q?=EB=A1=9C=EB=8D=95=EC=85=98=20=EC=BD=94=EB=93=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 +-- .../java/nextstep/courses/domain/Course.java | 12 ++++++ .../nextstep/courses/domain/CourseTest.java | 43 +++++++++++++++++++ 3 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 src/test/java/nextstep/courses/domain/CourseTest.java diff --git a/README.md b/README.md index 0035d05b07..e3b000406e 100644 --- a/README.md +++ b/README.md @@ -36,11 +36,11 @@ - [x] 학생은 수강신청을 할 수 있다. - [x] 수강 신청시 강의(Session)의 현재 수강 인원이 1 증가된다. - [x] 수강신청시 최대 인원을 넘게 되면 예외를 던진다. -- [ ] 수강 신청은 강의(Session) 의 상태가 `모집중` 일 때만 가능하다. - - [ ] `모집중`이 아닐 경우 예외를 던진다. +- [x] 수강 신청은 강의(Session) 의 상태가 `모집중` 일 때만 가능하다. + - [x] `모집중`이 아닐 경우 예외를 던진다. ### Course(과정) -- [ ] 강의를 과정에 추가하고, 기수에 따라 강의를 조회할 수 있다. +- [x] 강의를 과정에 추가하고, 기수에 따라 강의를 조회할 수 있다. - [ ] 기수가 유효하지 않다면 (음수 or 초과 기수 조회) 예외를 던진다. ### Session(강의) diff --git a/src/main/java/nextstep/courses/domain/Course.java b/src/main/java/nextstep/courses/domain/Course.java index 0f69716043..cbfe3760fe 100644 --- a/src/main/java/nextstep/courses/domain/Course.java +++ b/src/main/java/nextstep/courses/domain/Course.java @@ -1,6 +1,8 @@ package nextstep.courses.domain; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; public class Course { private Long id; @@ -9,6 +11,8 @@ public class Course { private Long creatorId; + private final List sessions = new ArrayList<>(); + private LocalDateTime createdAt; private LocalDateTime updatedAt; @@ -40,6 +44,14 @@ public LocalDateTime getCreatedAt() { return createdAt; } + public Session getSession(int index) { + return this.sessions.get(index - 1); + } + + public void addSession(Session session) { + this.sessions.add(session); + } + @Override public String toString() { return "Course{" + diff --git a/src/test/java/nextstep/courses/domain/CourseTest.java b/src/test/java/nextstep/courses/domain/CourseTest.java new file mode 100644 index 0000000000..99046873ae --- /dev/null +++ b/src/test/java/nextstep/courses/domain/CourseTest.java @@ -0,0 +1,43 @@ +package nextstep.courses.domain; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.time.LocalDateTime; + +public class CourseTest { + + private Course course; + private Session session1; + private Session session2; + private Session session3; + + @BeforeEach + void setUp() { + this.course = new Course(); + Long courseId = 1L; + SessionInfo sessionInfo = new SessionInfo(courseId, 1L, "titl1", "imageInfo", SessionType.FREE); + SessionStatus sessionStatus = SessionStatus.OPENED; + SessionTimeLine sessionTimeLine = new SessionTimeLine(LocalDateTime.now(), LocalDateTime.now().plusDays(10)); + + session1 = new Session(sessionInfo, sessionStatus, sessionTimeLine, 3L); + session2 = new Session(sessionInfo, sessionStatus, sessionTimeLine, 3L); + session3 = new Session(sessionInfo, sessionStatus, sessionTimeLine, 3L); + + course.addSession(session1); + course.addSession(session2); + course.addSession(session3); + } + + @Test + @DisplayName("기수에 따른 강의를 조회할 수 있다.") + void findCourse_DependOnId() { + Session session = course.getSession(1); + + Assertions.assertThat(session).isEqualTo(this.session1); + } + + +} From 6f18763f7886cf88100cc6ba65b62dd5e28b1ed2 Mon Sep 17 00:00:00 2001 From: highjune Date: Mon, 29 May 2023 03:11:21 +0900 Subject: [PATCH 20/27] =?UTF-8?q?test(domain):=20CourseTest=20=EC=A1=B4?= =?UTF-8?q?=EC=9E=AC=ED=95=98=EB=8A=94=20=EA=B0=95=EC=9D=98=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=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 --- .../java/nextstep/courses/domain/CourseTest.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/test/java/nextstep/courses/domain/CourseTest.java b/src/test/java/nextstep/courses/domain/CourseTest.java index 99046873ae..b6ccc180d2 100644 --- a/src/test/java/nextstep/courses/domain/CourseTest.java +++ b/src/test/java/nextstep/courses/domain/CourseTest.java @@ -4,6 +4,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import java.time.LocalDateTime; @@ -18,7 +20,7 @@ public class CourseTest { void setUp() { this.course = new Course(); Long courseId = 1L; - SessionInfo sessionInfo = new SessionInfo(courseId, 1L, "titl1", "imageInfo", SessionType.FREE); + SessionInfo sessionInfo = new SessionInfo(courseId, 1L, "title1", "coverImageInfo", SessionType.FREE); SessionStatus sessionStatus = SessionStatus.OPENED; SessionTimeLine sessionTimeLine = new SessionTimeLine(LocalDateTime.now(), LocalDateTime.now().plusDays(10)); @@ -33,11 +35,19 @@ void setUp() { @Test @DisplayName("기수에 따른 강의를 조회할 수 있다.") - void findCourse_DependOnId() { + void findSession_FromCourse_ContainExactly() { Session session = course.getSession(1); Assertions.assertThat(session).isEqualTo(this.session1); } + @ParameterizedTest + @DisplayName("기수에 따른 존재하는 강의를 조회시 예외를 던지지 않는다.") + @ValueSource(ints = {1, 2, 3}) + void findSession_FromCourseInExists_NoException(int value) { + Assertions.assertThatNoException() + .isThrownBy(() -> course.getSession(value)); + } + } From 456423ee9d52213979f2cb4c12b49a9656d6ec87 Mon Sep 17 00:00:00 2001 From: highjune Date: Mon, 29 May 2023 03:17:50 +0900 Subject: [PATCH 21/27] =?UTF-8?q?feat(domain):=20Course,=20CourseTest?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EC=9C=A0=ED=9A=A8=ED=95=98=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EB=8A=94=20=EA=B8=B0=EC=88=98=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=EC=8B=9C=20=EC=98=88=EC=99=B8=EB=A5=BC=20=EB=8D=98=EC=A7=84?= =?UTF-8?q?=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/nextstep/courses/domain/Course.java | 11 +++++++++-- .../nextstep/courses/domain/CourseTest.java | 19 ++++++++++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/main/java/nextstep/courses/domain/Course.java b/src/main/java/nextstep/courses/domain/Course.java index cbfe3760fe..61c9fba089 100644 --- a/src/main/java/nextstep/courses/domain/Course.java +++ b/src/main/java/nextstep/courses/domain/Course.java @@ -44,14 +44,21 @@ public LocalDateTime getCreatedAt() { return createdAt; } - public Session getSession(int index) { - return this.sessions.get(index - 1); + public Session getSession(int generation) { + validateGeneration(generation); + return this.sessions.get(generation - 1); } public void addSession(Session session) { this.sessions.add(session); } + private void validateGeneration(int generation) { + if (generation <= 0) { + throw new IllegalArgumentException("기수는 1 기수 이상부터 시작합니다. 현재 기수 = " + generation); + } + } + @Override public String toString() { return "Course{" + diff --git a/src/test/java/nextstep/courses/domain/CourseTest.java b/src/test/java/nextstep/courses/domain/CourseTest.java index b6ccc180d2..9272fa9df4 100644 --- a/src/test/java/nextstep/courses/domain/CourseTest.java +++ b/src/test/java/nextstep/courses/domain/CourseTest.java @@ -9,6 +9,8 @@ import java.time.LocalDateTime; +import static org.assertj.core.api.Assertions.*; + public class CourseTest { private Course course; @@ -38,16 +40,23 @@ void setUp() { void findSession_FromCourse_ContainExactly() { Session session = course.getSession(1); - Assertions.assertThat(session).isEqualTo(this.session1); + assertThat(session).isEqualTo(this.session1); } @ParameterizedTest @DisplayName("기수에 따른 존재하는 강의를 조회시 예외를 던지지 않는다.") @ValueSource(ints = {1, 2, 3}) - void findSession_FromCourseInExists_NoException(int value) { - Assertions.assertThatNoException() - .isThrownBy(() -> course.getSession(value)); + void findSession_FromCourseInExists_NoException(int generation) { + assertThatNoException() + .isThrownBy(() -> course.getSession(generation)); } - + @ParameterizedTest + @DisplayName("유효하지 않는 기수(음수, 0)를 조회시 예외를 발생한다.") + @ValueSource(ints = {-2, -1, 0}) + void findSession_ByInvalidValue_ThrowException(int generation) { + assertThatIllegalArgumentException() + .isThrownBy(() -> course.getSession(generation)) + .withMessageContaining("기수는 1 기수 이상부터 시작합니다."); + } } From 65577c09d3deafd4fa44ef14f141175d0d252b15 Mon Sep 17 00:00:00 2001 From: highjune Date: Mon, 29 May 2023 03:23:15 +0900 Subject: [PATCH 22/27] =?UTF-8?q?feat(domain):=20Course,=20CourseTest?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EC=9C=A0=ED=9A=A8=EC=84=B1=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/nextstep/courses/domain/Course.java | 13 ++++++++++++- .../java/nextstep/courses/domain/CourseTest.java | 11 ++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/main/java/nextstep/courses/domain/Course.java b/src/main/java/nextstep/courses/domain/Course.java index 61c9fba089..8c25e92ce7 100644 --- a/src/main/java/nextstep/courses/domain/Course.java +++ b/src/main/java/nextstep/courses/domain/Course.java @@ -54,8 +54,19 @@ public void addSession(Session session) { } private void validateGeneration(int generation) { + validateNegative(generation); + validateRange(generation); + } + + private void validateNegative(int generation) { if (generation <= 0) { - throw new IllegalArgumentException("기수는 1 기수 이상부터 시작합니다. 현재 기수 = " + generation); + throw new IllegalArgumentException("기수는 1 기수 이상부터 시작합니다. 조회한 기수 = " + generation); + } + } + + private void validateRange(int generation) { + if (sessions.size() < generation) { + throw new IllegalArgumentException("해당 기수의 강의는 존재하지 않습니다. 조회한 기수 = " + generation); } } diff --git a/src/test/java/nextstep/courses/domain/CourseTest.java b/src/test/java/nextstep/courses/domain/CourseTest.java index 9272fa9df4..160a266761 100644 --- a/src/test/java/nextstep/courses/domain/CourseTest.java +++ b/src/test/java/nextstep/courses/domain/CourseTest.java @@ -52,11 +52,20 @@ void findSession_FromCourseInExists_NoException(int generation) { } @ParameterizedTest - @DisplayName("유효하지 않는 기수(음수, 0)를 조회시 예외를 발생한다.") + @DisplayName("유효하지 않는 기수(음수, 0)를 조회시 예외를 던진다.") @ValueSource(ints = {-2, -1, 0}) void findSession_ByInvalidValue_ThrowException(int generation) { assertThatIllegalArgumentException() .isThrownBy(() -> course.getSession(generation)) .withMessageContaining("기수는 1 기수 이상부터 시작합니다."); } + + @Test + @DisplayName("존재하지 않는 기수 강의를 조회시 예의를 던진다.") + void findSession_IfNotExists_ThrowException() { + assertThatIllegalArgumentException() + .isThrownBy(() -> course.getSession(4)) + .withMessageContaining("해당 기수의 강의는 존재하지 않습니다."); + + } } From cefcc3e3ddd54002a76cde22d1dc396e81f01df5 Mon Sep 17 00:00:00 2001 From: highjune Date: Mon, 29 May 2023 03:25:17 +0900 Subject: [PATCH 23/27] =?UTF-8?q?feat(domain):=20SessionRepository=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/nextstep/courses/domain/Course.java | 1 + .../nextstep/courses/domain/SessionRepository.java | 12 ++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 src/main/java/nextstep/courses/domain/SessionRepository.java diff --git a/src/main/java/nextstep/courses/domain/Course.java b/src/main/java/nextstep/courses/domain/Course.java index 8c25e92ce7..ad58b93788 100644 --- a/src/main/java/nextstep/courses/domain/Course.java +++ b/src/main/java/nextstep/courses/domain/Course.java @@ -76,6 +76,7 @@ public String toString() { "id=" + id + ", title='" + title + '\'' + ", creatorId=" + creatorId + + ", sessions=" + sessions + ", createdAt=" + createdAt + ", updatedAt=" + updatedAt + '}'; diff --git a/src/main/java/nextstep/courses/domain/SessionRepository.java b/src/main/java/nextstep/courses/domain/SessionRepository.java new file mode 100644 index 0000000000..2dcb8f48d6 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/SessionRepository.java @@ -0,0 +1,12 @@ +package nextstep.courses.domain; + +import java.util.List; + +public interface SessionRepository { + + int save(String session); + + Session findById(Long id); + + List findByCourseId(Long courseId); +} From 8058c79f7921773482675a840eceb05cbea8b342 Mon Sep 17 00:00:00 2001 From: highjune Date: Mon, 29 May 2023 03:29:05 +0900 Subject: [PATCH 24/27] =?UTF-8?q?docs(README.md):=20Course=20=EC=B2=B4?= =?UTF-8?q?=ED=81=AC=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e3b000406e..9eec5cd0f7 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ ### Course(과정) - [x] 강의를 과정에 추가하고, 기수에 따라 강의를 조회할 수 있다. -- [ ] 기수가 유효하지 않다면 (음수 or 초과 기수 조회) 예외를 던진다. +- [x] 기수가 유효하지 않다면 (음수 or 초과 기수 조회) 예외를 던진다. ### Session(강의) - [x] 시작일과 종료일을 가진다. From aee8314d797d17f7f52df3f4b015e685b7911292 Mon Sep 17 00:00:00 2001 From: highjune Date: Wed, 31 May 2023 22:06:31 +0900 Subject: [PATCH 25/27] =?UTF-8?q?feat(domain):=20Session=EC=97=90=20?= =?UTF-8?q?=EB=93=B1=EB=A1=9D=ED=95=98=EB=8A=94=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - add -> enroll --- .../java/nextstep/courses/domain/Session.java | 2 +- .../java/nextstep/courses/domain/Student.java | 2 +- .../nextstep/courses/domain/StudentTest.java | 19 +++++++++---------- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/main/java/nextstep/courses/domain/Session.java b/src/main/java/nextstep/courses/domain/Session.java index 66cf95c04e..0acd8c013b 100644 --- a/src/main/java/nextstep/courses/domain/Session.java +++ b/src/main/java/nextstep/courses/domain/Session.java @@ -32,7 +32,7 @@ public Session(SessionInfo sessionInfo, SessionStatus sessionStatus, this.maxNumberOfStudent = maxNumberOfStudent; } - public void add(Student student) { + public void enroll(Student student) { if (!sessionStatus.canJoin()) { throw new CannotEnrollException("현재는 수강신청을 할 수 없는 강의 상태입니다. 현재 강의 상태 = " + sessionStatus.name()); } diff --git a/src/main/java/nextstep/courses/domain/Student.java b/src/main/java/nextstep/courses/domain/Student.java index bf2dfe6944..8b71cc4589 100644 --- a/src/main/java/nextstep/courses/domain/Student.java +++ b/src/main/java/nextstep/courses/domain/Student.java @@ -11,6 +11,6 @@ public Student(Long studentId, Long sessionId) { } public void enroll(Session session) { - session.add(this); + session.enroll(this); } } diff --git a/src/test/java/nextstep/courses/domain/StudentTest.java b/src/test/java/nextstep/courses/domain/StudentTest.java index 5f1e06a38b..1ff488b6f7 100644 --- a/src/test/java/nextstep/courses/domain/StudentTest.java +++ b/src/test/java/nextstep/courses/domain/StudentTest.java @@ -1,6 +1,5 @@ package nextstep.courses.domain; -import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -32,10 +31,10 @@ void enroll_SessionMaxNumberOfValue_PlusOne() { @Test @DisplayName("수강신청시 최대 수강신청 인원을 넘을 경우 예외를 던진다.") void enroll_OutOfMaxNumberOfStudent_ThrowException() { - session.add(june1); - session.add(june2); + session.enroll(june1); + session.enroll(june2); - assertThatThrownBy(() -> session.add(june3)) + assertThatThrownBy(() -> session.enroll(june3)) .isInstanceOf(CannotEnrollException.class) .hasMessageContaining("현재 강의(Session)는 수강인원이 꽉 차서 더 이상 등록할 수 없습니다."); } @@ -45,9 +44,9 @@ void enroll_OutOfMaxNumberOfStudent_ThrowException() { void enroll_LessThanMaxNumberOfStudent_NoException() { Session session = SessionCreator.create(3L, SessionStatus.OPENED); - assertThatNoException().isThrownBy(() -> session.add(june1)); - assertThatNoException().isThrownBy(() -> session.add(june2)); - assertThatNoException().isThrownBy(() -> session.add(june3)); + assertThatNoException().isThrownBy(() -> session.enroll(june1)); + assertThatNoException().isThrownBy(() -> session.enroll(june2)); + assertThatNoException().isThrownBy(() -> session.enroll(june3)); } @Test @@ -55,7 +54,7 @@ void enroll_LessThanMaxNumberOfStudent_NoException() { void enroll_SessionStatus_OPENED_NoException() { Session session = SessionCreator.create(3L, SessionStatus.OPENED); - assertThatNoException().isThrownBy(() -> session.add(june1)); + assertThatNoException().isThrownBy(() -> session.enroll(june1)); } @Test @@ -63,7 +62,7 @@ void enroll_SessionStatus_OPENED_NoException() { void enroll_SessionStatus_READY_ThrowException() { Session session = SessionCreator.create(3L, SessionStatus.READY); - assertThatThrownBy(() -> session.add(june1)) + assertThatThrownBy(() -> session.enroll(june1)) .isInstanceOf(CannotEnrollException.class); } @@ -73,7 +72,7 @@ void enroll_SessionStatus_READY_ThrowException() { void enroll_SessionStatus_CLOSED_ThrowException() { Session session = SessionCreator.create(3L, SessionStatus.CLSOED); - assertThatThrownBy(() -> session.add(june1)) + assertThatThrownBy(() -> session.enroll(june1)) .isInstanceOf(CannotEnrollException.class); } From 39ad05a3bd581e426326b6891ce53dab5bb697b9 Mon Sep 17 00:00:00 2001 From: highjune Date: Wed, 31 May 2023 23:17:50 +0900 Subject: [PATCH 26/27] =?UTF-8?q?feat(SessionEnrollment):=20=EA=B0=95?= =?UTF-8?q?=EC=9D=98=EB=93=B1=EB=A1=9D=20=EA=B0=9D=EC=B2=B4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80,=20=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 - SessionEnrollment 객체 구현 완료 - SessionEnrollmentTest 테스트 추가 - Session 에서 강의 등록에 관련 있는 3개의 멤버변수를 빼서 SessionEnrollment로 분리 완료 --- .../java/nextstep/courses/domain/Session.java | 38 +++------ .../courses/domain/SessionEnrollment.java | 37 ++++++++ .../nextstep/courses/domain/CourseTest.java | 8 +- .../courses/domain/SessionCreator.java | 3 +- .../courses/domain/SessionEnrollmentTest.java | 85 +++++++++++++++++++ 5 files changed, 139 insertions(+), 32 deletions(-) create mode 100644 src/main/java/nextstep/courses/domain/SessionEnrollment.java create mode 100644 src/test/java/nextstep/courses/domain/SessionEnrollmentTest.java diff --git a/src/main/java/nextstep/courses/domain/Session.java b/src/main/java/nextstep/courses/domain/Session.java index 0acd8c013b..aa3a6d7570 100644 --- a/src/main/java/nextstep/courses/domain/Session.java +++ b/src/main/java/nextstep/courses/domain/Session.java @@ -1,54 +1,38 @@ package nextstep.courses.domain; import java.time.LocalDateTime; -import java.util.HashSet; -import java.util.Set; public class Session { - private final SessionInfo sessionInfo; - private final SessionStatus sessionStatus; + private final SessionEnrollment sessionEnrollment; private final SessionTimeLine sessionTimeLine; - private final Set students = new HashSet<>(); - private final Long maxNumberOfStudent; public Session(Long courseId, Long ownerId, String title, String coverImageInfo, SessionType sessionType, SessionStatus sessionStatus, LocalDateTime createdAt, LocalDateTime closedAt, Long maxNumOfStudent) { this(new SessionInfo(courseId, ownerId, title, coverImageInfo, sessionType), - sessionStatus, - new SessionTimeLine(createdAt, closedAt), - maxNumOfStudent - ); + new SessionEnrollment(sessionStatus, maxNumOfStudent), + new SessionTimeLine(createdAt, closedAt)); } - public Session(SessionInfo sessionInfo, SessionStatus sessionStatus, - SessionTimeLine sessionTimeLine, Long maxNumberOfStudent){ + public Session(SessionInfo sessionInfo, SessionEnrollment sessionEnrollment, + SessionTimeLine sessionTimeLine){ this.sessionInfo = sessionInfo; - this.sessionStatus = sessionStatus; + this.sessionEnrollment = sessionEnrollment; this.sessionTimeLine = sessionTimeLine; - this.maxNumberOfStudent = maxNumberOfStudent; } public void enroll(Student student) { - if (!sessionStatus.canJoin()) { - throw new CannotEnrollException("현재는 수강신청을 할 수 없는 강의 상태입니다. 현재 강의 상태 = " + sessionStatus.name()); - } - - if (isPositionFull()) { - throw new CannotEnrollException( - "현재 강의(Session)는 수강인원이 꽉 차서 더 이상 등록할 수 없습니다." + "최대인원 = " + maxNumberOfStudent); - } - this.students.add(student); + sessionEnrollment.enroll(student); } - public int totalStudentNum() { - return students.size(); + public Long totalStudentNum() { + return sessionEnrollment.totalStudentNum(); } - private boolean isPositionFull() { - return totalStudentNum() == maxNumberOfStudent; + public boolean isPositionFull() { + return sessionEnrollment.isPositionFull(); } } diff --git a/src/main/java/nextstep/courses/domain/SessionEnrollment.java b/src/main/java/nextstep/courses/domain/SessionEnrollment.java new file mode 100644 index 0000000000..aa60d4e9d2 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/SessionEnrollment.java @@ -0,0 +1,37 @@ +package nextstep.courses.domain; + +import java.util.HashSet; +import java.util.Set; + +public class SessionEnrollment { + + private final SessionStatus sessionStatus; + private final Set students = new HashSet<>(); + private final Long maxNumberOfStudent; + + public SessionEnrollment(SessionStatus sessionStatus, Long maxNumberOfStudent) { + this.sessionStatus = sessionStatus; + this.maxNumberOfStudent = maxNumberOfStudent; + } + + public void enroll(Student student) { + if (!sessionStatus.canJoin()) { + throw new CannotEnrollException("현재는 수강신청을 할 수 없는 강의 상태입니다. 현재 강의 상태 = " + sessionStatus.name()); + } + + if (isPositionFull()) { + throw new CannotEnrollException( + "현재 강의(Session)는 수강인원이 꽉 차서 더 이상 등록할 수 없습니다." + "최대인원 = " + maxNumberOfStudent); + } + this.students.add(student); + } + + public Long totalStudentNum() { + return Long.valueOf(students.size()); + } + + public boolean isPositionFull() { + return totalStudentNum() == maxNumberOfStudent; + } + +} diff --git a/src/test/java/nextstep/courses/domain/CourseTest.java b/src/test/java/nextstep/courses/domain/CourseTest.java index 160a266761..6a910d13bd 100644 --- a/src/test/java/nextstep/courses/domain/CourseTest.java +++ b/src/test/java/nextstep/courses/domain/CourseTest.java @@ -1,6 +1,5 @@ package nextstep.courses.domain; -import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -24,11 +23,12 @@ void setUp() { Long courseId = 1L; SessionInfo sessionInfo = new SessionInfo(courseId, 1L, "title1", "coverImageInfo", SessionType.FREE); SessionStatus sessionStatus = SessionStatus.OPENED; + SessionEnrollment sessionEnrollment = new SessionEnrollment(sessionStatus, 3L); SessionTimeLine sessionTimeLine = new SessionTimeLine(LocalDateTime.now(), LocalDateTime.now().plusDays(10)); - session1 = new Session(sessionInfo, sessionStatus, sessionTimeLine, 3L); - session2 = new Session(sessionInfo, sessionStatus, sessionTimeLine, 3L); - session3 = new Session(sessionInfo, sessionStatus, sessionTimeLine, 3L); + session1 = new Session(sessionInfo, sessionEnrollment, sessionTimeLine); + session2 = new Session(sessionInfo, sessionEnrollment, sessionTimeLine); + session3 = new Session(sessionInfo, sessionEnrollment, sessionTimeLine); course.addSession(session1); course.addSession(session2); diff --git a/src/test/java/nextstep/courses/domain/SessionCreator.java b/src/test/java/nextstep/courses/domain/SessionCreator.java index c2a2f23259..b2f1a3c78c 100644 --- a/src/test/java/nextstep/courses/domain/SessionCreator.java +++ b/src/test/java/nextstep/courses/domain/SessionCreator.java @@ -7,7 +7,8 @@ public class SessionCreator { public static Session create(Long maxNumberOfStudent, SessionStatus sessionStatus) { SessionInfo sessionInfo = new SessionInfo(1L, 0L, "titleName", "coverImage", SessionType.FREE); + SessionEnrollment sessionEnrollment = new SessionEnrollment(sessionStatus, maxNumberOfStudent); SessionTimeLine sessionTimeLine = new SessionTimeLine(LocalDateTime.now(), LocalDateTime.now().plusDays(10)); - return new Session(sessionInfo, sessionStatus, sessionTimeLine, maxNumberOfStudent); + return new Session(sessionInfo, sessionEnrollment, sessionTimeLine); } } diff --git a/src/test/java/nextstep/courses/domain/SessionEnrollmentTest.java b/src/test/java/nextstep/courses/domain/SessionEnrollmentTest.java new file mode 100644 index 0000000000..b4ed46da18 --- /dev/null +++ b/src/test/java/nextstep/courses/domain/SessionEnrollmentTest.java @@ -0,0 +1,85 @@ +package nextstep.courses.domain; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.*; + +public class SessionEnrollmentTest { + + Student june1; + Student june2; + Student june3; + + @BeforeEach + void setUp() { + june1 = new Student(0L, 10L); + june2 = new Student(0L, 10L); + june3 = new Student(0L, 10L); + } + + @Test + @DisplayName("학생은 수강신청시 강의의 현재 수강인원이 1이 증가한다.") + void enroll_SessionMaxNumberOfValue_PlusOne() { + SessionEnrollment sessionEnrollment = + new SessionEnrollment(SessionStatus.OPENED, 3l); + + sessionEnrollment.enroll(june1); + + assertThat(sessionEnrollment.totalStudentNum()).isEqualTo(1l); + } + + @Test + @DisplayName("수강신청시 최대 수강신청 인원을 넘을 경우 예외를 던진다.") + void enroll_OutOfMaxNumberOfStudent_ThrowException() { + SessionEnrollment sessionEnrollment = + new SessionEnrollment(SessionStatus.OPENED, 0l); + + assertThatThrownBy(() -> sessionEnrollment.enroll(june1)) + .isInstanceOf(CannotEnrollException.class) + .hasMessageContaining("현재 강의(Session)는 수강인원이 꽉 차서 더 이상 등록할 수 없습니다."); + } + + @Test + @DisplayName("수강신청시 최대 수강인원을 넘지 않을 경우 예외를 던지지 않는다.") + void enroll_LessThanMaxNumberOfStudent_NoException() { + SessionEnrollment sessionEnrollment = + new SessionEnrollment(SessionStatus.OPENED, 3l); + + assertThatNoException().isThrownBy(() -> sessionEnrollment.enroll(june1)); + assertThatNoException().isThrownBy(() -> sessionEnrollment.enroll(june2)); + assertThatNoException().isThrownBy(() -> sessionEnrollment.enroll(june3)); + } + + @Test + @DisplayName("강의 상태(SessionStatus) '모집중'일 경우에 수강신청이 가능하다(예외를 던지지 않는다.") + void enroll_SessionStatus_OPENED_NoException() { + SessionEnrollment sessionEnrollment = + new SessionEnrollment(SessionStatus.OPENED, 3l); + + assertThatNoException().isThrownBy(() -> sessionEnrollment.enroll(june1)); + } + + @Test + @DisplayName("강의 상태(SessionStatus) '준비중'일 경우에 수깅신청시 예외를 던진다.") + void enroll_SessionStatus_READY_ThrowException() { + SessionEnrollment sessionEnrollment = + new SessionEnrollment(SessionStatus.READY, 3l); + + assertThatThrownBy(() -> sessionEnrollment.enroll(june1)) + .isInstanceOf(CannotEnrollException.class) + .hasMessageContaining("현재는 수강신청을 할 수 없는 강의 상태입니다."); + } + + @Test + @DisplayName("강의 상태(SessionStatus) '종료'일 경우에 수깅신청시 예외를 던진다.") + void enroll_SessionStatus_CLOSED_ThrowException() { + SessionEnrollment sessionEnrollment = + new SessionEnrollment(SessionStatus.CLSOED, 3l); + + assertThatThrownBy(() -> sessionEnrollment.enroll(june1)) + .isInstanceOf(CannotEnrollException.class) + .hasMessageContaining("현재는 수강신청을 할 수 없는 강의 상태입니다."); + } +} \ No newline at end of file From 33d78896c9cc26198cfb4c7391adb679d6046840 Mon Sep 17 00:00:00 2001 From: highjune Date: Thu, 1 Jun 2023 20:39:37 +0900 Subject: [PATCH 27/27] =?UTF-8?q?feat(domain):=20SessionEnrollment=20?= =?UTF-8?q?=EC=97=90=20=EC=9C=A0=ED=9A=A8=EC=84=B1=20=EC=B2=B4=ED=81=AC=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 이미 등록을 한 학생인 경우 예외를 던진다. - README.md 추가 - AlreadyEnrollmentException 추가 - 테스트 추가 --- README.md | 11 +++++++++++ .../domain/AlreadyEnrollmentException.java | 8 ++++++++ .../courses/domain/SessionEnrollment.java | 14 +++++++++----- .../courses/domain/SessionEnrollmentTest.java | 15 ++++++++++++++- 4 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 src/main/java/nextstep/courses/domain/AlreadyEnrollmentException.java diff --git a/README.md b/README.md index 9eec5cd0f7..c58093a8e5 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,17 @@ - status(상태) - [x] 준비중, 모집중, 종료 3가지를 가진다(enum) +### SessionEnrollment(등록) +- [x] 이미 등록을 한 학생은 예외를 던진다. +- [x] 수용인원이 꽉 찬 강의에 등록시도를 할 경에 예외를 던진다. + - [x] 수강신청시 최대 수강인원을 넘지 않을 경우 예외를 던지지 않는다. +- [x] 학생은 수강신청시 강의의 현재 수강인원이 1이 증가한다. +- 강의 상태에 따라 등록상태가 다르다. + - [x] 강의 상태(SessionStatus) '모집중'일 경우에 수강신청이 가능하다(예외를 던지지 않는다) + - [x] 강의 상태(SessionStatus) '준비중'일 경우에 수깅신청시 예외를 던진다. + - [x] 강의 상태(SessionStatus) '종료'일 경우에 수깅신청시 예외를 던진다. + + ### 수강 신청 기능 요구사항 - 과정(Course)은 기수 단위로 여러 개의 강의(Session)를 가질 수 있다. - 강의는 시작일과 종료일을 가진다. diff --git a/src/main/java/nextstep/courses/domain/AlreadyEnrollmentException.java b/src/main/java/nextstep/courses/domain/AlreadyEnrollmentException.java new file mode 100644 index 0000000000..117b58ecd4 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/AlreadyEnrollmentException.java @@ -0,0 +1,8 @@ +package nextstep.courses.domain; + +public class AlreadyEnrollmentException extends RuntimeException{ + + public AlreadyEnrollmentException(String message) { + super(message); + } +} diff --git a/src/main/java/nextstep/courses/domain/SessionEnrollment.java b/src/main/java/nextstep/courses/domain/SessionEnrollment.java index aa60d4e9d2..e9d7f9c26d 100644 --- a/src/main/java/nextstep/courses/domain/SessionEnrollment.java +++ b/src/main/java/nextstep/courses/domain/SessionEnrollment.java @@ -7,11 +7,11 @@ public class SessionEnrollment { private final SessionStatus sessionStatus; private final Set students = new HashSet<>(); - private final Long maxNumberOfStudent; + private final Long capacity; - public SessionEnrollment(SessionStatus sessionStatus, Long maxNumberOfStudent) { + public SessionEnrollment(SessionStatus sessionStatus, Long capacity) { this.sessionStatus = sessionStatus; - this.maxNumberOfStudent = maxNumberOfStudent; + this.capacity = capacity; } public void enroll(Student student) { @@ -21,7 +21,11 @@ public void enroll(Student student) { if (isPositionFull()) { throw new CannotEnrollException( - "현재 강의(Session)는 수강인원이 꽉 차서 더 이상 등록할 수 없습니다." + "최대인원 = " + maxNumberOfStudent); + "현재 강의(Session)는 수강인원이 꽉 차서 더 이상 등록할 수 없습니다." + "최대인원 = " + capacity); + } + + if (students.contains(student)) { + throw new AlreadyEnrollmentException(student + " 학생은 이미 등록한 상태입니다."); } this.students.add(student); } @@ -31,7 +35,7 @@ public Long totalStudentNum() { } public boolean isPositionFull() { - return totalStudentNum() == maxNumberOfStudent; + return totalStudentNum() == capacity; } } diff --git a/src/test/java/nextstep/courses/domain/SessionEnrollmentTest.java b/src/test/java/nextstep/courses/domain/SessionEnrollmentTest.java index b4ed46da18..a9e003271f 100644 --- a/src/test/java/nextstep/courses/domain/SessionEnrollmentTest.java +++ b/src/test/java/nextstep/courses/domain/SessionEnrollmentTest.java @@ -53,7 +53,7 @@ void enroll_LessThanMaxNumberOfStudent_NoException() { } @Test - @DisplayName("강의 상태(SessionStatus) '모집중'일 경우에 수강신청이 가능하다(예외를 던지지 않는다.") + @DisplayName("강의 상태(SessionStatus) '모집중'일 경우에 수강신청이 가능하다(예외를 던지지 않는다).") void enroll_SessionStatus_OPENED_NoException() { SessionEnrollment sessionEnrollment = new SessionEnrollment(SessionStatus.OPENED, 3l); @@ -82,4 +82,17 @@ void enroll_SessionStatus_CLOSED_ThrowException() { .isInstanceOf(CannotEnrollException.class) .hasMessageContaining("현재는 수강신청을 할 수 없는 강의 상태입니다."); } + + @Test + @DisplayName("이미 등록된 학생의 경우 예외를 던진다.") + void enroll_AlreadyEnrollStudent_Duplicate_ThrowException() { + SessionEnrollment sessionEnrollment = + new SessionEnrollment(SessionStatus.OPENED, 3l); + + sessionEnrollment.enroll(june1); + + assertThatThrownBy(() -> sessionEnrollment.enroll(june1)) + .isInstanceOf(AlreadyEnrollmentException.class) + .hasMessageContaining("학생은 이미 등록한 상태입니다."); + } } \ No newline at end of file