diff --git a/backend/src/main/java/reviewme/review/service/dto/request/ReviewAnswerRequest.java b/backend/src/main/java/reviewme/review/service/dto/request/ReviewAnswerRequest.java index 60233be2d..85d89cd7e 100644 --- a/backend/src/main/java/reviewme/review/service/dto/request/ReviewAnswerRequest.java +++ b/backend/src/main/java/reviewme/review/service/dto/request/ReviewAnswerRequest.java @@ -15,11 +15,12 @@ public record ReviewAnswerRequest( @Nullable String text ) { - public boolean hasTextAnswer() { - return text != null && !text.isEmpty(); + + public boolean hasNoText() { + return text == null || text.isBlank(); } - public boolean hasCheckboxAnswer() { - return selectedOptionIds != null && !selectedOptionIds.isEmpty(); + public boolean hasNoSelectedOptions() { + return selectedOptionIds == null || selectedOptionIds.isEmpty(); } } diff --git a/backend/src/main/java/reviewme/review/service/mapper/AnswerMapper.java b/backend/src/main/java/reviewme/review/service/mapper/AnswerMapper.java index 1181808a5..87ee4c511 100644 --- a/backend/src/main/java/reviewme/review/service/mapper/AnswerMapper.java +++ b/backend/src/main/java/reviewme/review/service/mapper/AnswerMapper.java @@ -1,8 +1,8 @@ package reviewme.review.service.mapper; -import reviewme.template.domain.QuestionType; import reviewme.review.domain.Answer; import reviewme.review.service.dto.request.ReviewAnswerRequest; +import reviewme.template.domain.QuestionType; public interface AnswerMapper { diff --git a/backend/src/main/java/reviewme/review/service/mapper/CheckboxAnswerMapper.java b/backend/src/main/java/reviewme/review/service/mapper/CheckboxAnswerMapper.java index 7fb87b0dc..2829890cd 100644 --- a/backend/src/main/java/reviewme/review/service/mapper/CheckboxAnswerMapper.java +++ b/backend/src/main/java/reviewme/review/service/mapper/CheckboxAnswerMapper.java @@ -1,10 +1,9 @@ package reviewme.review.service.mapper; import org.springframework.stereotype.Component; -import reviewme.template.domain.QuestionType; import reviewme.review.domain.CheckboxAnswer; import reviewme.review.service.dto.request.ReviewAnswerRequest; -import reviewme.review.service.exception.CheckBoxAnswerIncludedTextException; +import reviewme.template.domain.QuestionType; @Component public class CheckboxAnswerMapper implements AnswerMapper { @@ -16,8 +15,8 @@ public boolean supports(QuestionType questionType) { @Override public CheckboxAnswer mapToAnswer(ReviewAnswerRequest answerRequest) { - if (answerRequest.text() != null) { - throw new CheckBoxAnswerIncludedTextException(answerRequest.questionId()); + if (answerRequest.hasNoSelectedOptions()) { + return null; } return new CheckboxAnswer(answerRequest.questionId(), answerRequest.selectedOptionIds()); } diff --git a/backend/src/main/java/reviewme/review/service/mapper/ReviewMapper.java b/backend/src/main/java/reviewme/review/service/mapper/ReviewMapper.java index 58d0c6a6f..499a5ea19 100644 --- a/backend/src/main/java/reviewme/review/service/mapper/ReviewMapper.java +++ b/backend/src/main/java/reviewme/review/service/mapper/ReviewMapper.java @@ -62,20 +62,10 @@ private List getAnswersByQuestionType(ReviewRegisterRequest request) { private Answer mapRequestToAnswer(Map questions, ReviewAnswerRequest answerRequest) { Question question = questions.get(answerRequest.questionId()); - if (question == null) { throw new SubmittedQuestionNotFoundException(answerRequest.questionId()); } - // TODO: 아래 코드를 삭제해야 한다 - if (question.isSelectable() && answerRequest.selectedOptionIds() != null && answerRequest.selectedOptionIds().isEmpty()) { - return null; - } - if (!question.isSelectable() && answerRequest.text() != null && answerRequest.text().isEmpty()) { - return null; - } - // END - AnswerMapper answerMapper = answerMapperFactory.getAnswerMapper(question.getQuestionType()); return answerMapper.mapToAnswer(answerRequest); } diff --git a/backend/src/main/java/reviewme/review/service/mapper/TextAnswerMapper.java b/backend/src/main/java/reviewme/review/service/mapper/TextAnswerMapper.java index 48bd55789..6f28faedd 100644 --- a/backend/src/main/java/reviewme/review/service/mapper/TextAnswerMapper.java +++ b/backend/src/main/java/reviewme/review/service/mapper/TextAnswerMapper.java @@ -1,10 +1,9 @@ package reviewme.review.service.mapper; import org.springframework.stereotype.Component; -import reviewme.template.domain.QuestionType; import reviewme.review.domain.TextAnswer; import reviewme.review.service.dto.request.ReviewAnswerRequest; -import reviewme.review.service.exception.TextAnswerIncludedOptionItemException; +import reviewme.template.domain.QuestionType; @Component public class TextAnswerMapper implements AnswerMapper { @@ -16,12 +15,9 @@ public boolean supports(QuestionType questionType) { @Override public TextAnswer mapToAnswer(ReviewAnswerRequest answerRequest) { - if (!answerRequest.hasTextAnswer()) { + if (answerRequest.hasNoText()) { return null; } - if (answerRequest.selectedOptionIds() != null) { - throw new TextAnswerIncludedOptionItemException(answerRequest.questionId()); - } return new TextAnswer(answerRequest.questionId(), answerRequest.text()); } } diff --git a/backend/src/test/java/reviewme/review/service/mapper/AnswerMapperFactoryTest.java b/backend/src/test/java/reviewme/review/service/mapper/AnswerMapperFactoryTest.java index bdf37e905..f18dc74f3 100644 --- a/backend/src/test/java/reviewme/review/service/mapper/AnswerMapperFactoryTest.java +++ b/backend/src/test/java/reviewme/review/service/mapper/AnswerMapperFactoryTest.java @@ -8,9 +8,9 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.test.system.CapturedOutput; import org.springframework.boot.test.system.OutputCaptureExtension; -import reviewme.template.domain.QuestionType; import reviewme.review.domain.Answer; import reviewme.review.service.dto.request.ReviewAnswerRequest; +import reviewme.template.domain.QuestionType; @ExtendWith(OutputCaptureExtension.class) class AnswerMapperFactoryTest { @@ -18,13 +18,13 @@ class AnswerMapperFactoryTest { private final AnswerMapper answerMapper = new AnswerMapper() { @Override - public boolean supports(QuestionType questionType) { - return questionType == QuestionType.CHECKBOX; + public Answer mapToAnswer(ReviewAnswerRequest answerRequest) { + return null; } @Override - public Answer mapToAnswer(ReviewAnswerRequest answerRequest) { - return null; + public boolean supports(QuestionType questionType) { + return questionType == QuestionType.CHECKBOX; } }; diff --git a/backend/src/test/java/reviewme/review/service/mapper/CheckboxAnswerMapperTest.java b/backend/src/test/java/reviewme/review/service/mapper/CheckboxAnswerMapperTest.java index eb2d96f98..c05b4553f 100644 --- a/backend/src/test/java/reviewme/review/service/mapper/CheckboxAnswerMapperTest.java +++ b/backend/src/test/java/reviewme/review/service/mapper/CheckboxAnswerMapperTest.java @@ -1,14 +1,14 @@ package reviewme.review.service.mapper; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.util.List; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; import reviewme.review.domain.CheckboxAnswer; import reviewme.review.domain.CheckboxAnswerSelectedOption; import reviewme.review.service.dto.request.ReviewAnswerRequest; -import reviewme.review.service.exception.CheckBoxAnswerIncludedTextException; class CheckboxAnswerMapperTest { @@ -28,16 +28,17 @@ class CheckboxAnswerMapperTest { .containsExactly(1L, 2L, 3L); } - @Test - void 체크박스_답변_요청에_텍스트가_포함되어_있으면_예외를_발생시킨다() { + @ParameterizedTest + @NullAndEmptySource + void 체크박스_답변이_비어있는_경우_null로_매핑한다(List selectedOptionIds) { // given - ReviewAnswerRequest request = new ReviewAnswerRequest(1L, List.of(1L, 2L, 3L), "text"); + ReviewAnswerRequest request = new ReviewAnswerRequest(1L, selectedOptionIds, null); + CheckboxAnswerMapper mapper = new CheckboxAnswerMapper(); // when - CheckboxAnswerMapper mapper = new CheckboxAnswerMapper(); + CheckboxAnswer actual = mapper.mapToAnswer(request); // then - assertThatThrownBy(() -> mapper.mapToAnswer(request)) - .isInstanceOf(CheckBoxAnswerIncludedTextException.class); + assertThat(actual).isNull(); } } diff --git a/backend/src/test/java/reviewme/review/service/mapper/ReviewMapperTest.java b/backend/src/test/java/reviewme/review/service/mapper/ReviewMapperTest.java index 4065c63de..2a624ccf5 100644 --- a/backend/src/test/java/reviewme/review/service/mapper/ReviewMapperTest.java +++ b/backend/src/test/java/reviewme/review/service/mapper/ReviewMapperTest.java @@ -2,7 +2,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.jupiter.api.Assertions.assertAll; import static reviewme.fixture.OptionGroupFixture.선택지_그룹; import static reviewme.fixture.OptionItemFixture.선택지; import static reviewme.fixture.QuestionFixture.서술형_옵션_질문; @@ -16,12 +15,6 @@ import java.util.List; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import reviewme.template.domain.OptionGroup; -import reviewme.template.domain.OptionItem; -import reviewme.template.domain.Question; -import reviewme.template.repository.OptionGroupRepository; -import reviewme.template.repository.OptionItemRepository; -import reviewme.template.repository.QuestionRepository; import reviewme.review.domain.CheckboxAnswer; import reviewme.review.domain.Review; import reviewme.review.domain.TextAnswer; @@ -31,7 +24,13 @@ import reviewme.reviewgroup.domain.ReviewGroup; import reviewme.reviewgroup.repository.ReviewGroupRepository; import reviewme.support.ServiceTest; +import reviewme.template.domain.OptionGroup; +import reviewme.template.domain.OptionItem; +import reviewme.template.domain.Question; import reviewme.template.domain.Section; +import reviewme.template.repository.OptionGroupRepository; +import reviewme.template.repository.OptionItemRepository; +import reviewme.template.repository.QuestionRepository; import reviewme.template.repository.SectionRepository; import reviewme.template.repository.TemplateRepository; @@ -60,7 +59,7 @@ class ReviewMapperTest { private TemplateRepository templateRepository; @Test - void 텍스트가_포함된_리뷰를_생성한다() { + void 서술형_답변을_매핑한다() { // given ReviewGroup reviewGroup = reviewGroupRepository.save(리뷰_그룹()); @@ -81,7 +80,7 @@ class ReviewMapperTest { } @Test - void 체크박스가_포함된_리뷰를_생성한다() { + void 선택형_답변을_매핑한다() { // given ReviewGroup reviewGroup = reviewGroupRepository.save(리뷰_그룹()); @@ -106,57 +105,47 @@ class ReviewMapperTest { } @Test - void 필수가_아닌_질문에_답변이_없을_경우_답변을_생성하지_않는다() { + void 필수가_아닌_서술형_질문에_답변이_없으면_매핑하지_않는다() { // given ReviewGroup reviewGroup = reviewGroupRepository.save(리뷰_그룹()); + Question question = questionRepository.save(서술형_옵션_질문()); + Section section = sectionRepository.save(항상_보이는_섹션(List.of(question.getId()))); + templateRepository.save(템플릿(List.of(section.getId()))); - Question requiredTextQuestion = questionRepository.save(서술형_필수_질문()); - Question optionalTextQuestion = questionRepository.save(서술형_옵션_질문()); + ReviewAnswerRequest answerRequest = new ReviewAnswerRequest(question.getId(), null, ""); + ReviewRegisterRequest reviewRegisterRequest = new ReviewRegisterRequest( + reviewGroup.getReviewRequestCode(), List.of(answerRequest)); - Question requeiredCheckBoxQuestion = questionRepository.save(선택형_필수_질문()); - OptionGroup optionGroup1 = optionGroupRepository.save(선택지_그룹(requeiredCheckBoxQuestion.getId())); - OptionItem optionItem1 = optionItemRepository.save(선택지(optionGroup1.getId())); - OptionItem optionItem2 = optionItemRepository.save(선택지(optionGroup1.getId())); + // when + Review review = reviewMapper.mapToReview(reviewRegisterRequest); - Question optionalCheckBoxQuestion = questionRepository.save(선택형_옵션_질문()); - OptionGroup optionGroup2 = optionGroupRepository.save(선택지_그룹(optionalCheckBoxQuestion.getId())); - OptionItem optionItem3 = optionItemRepository.save(선택지(optionGroup2.getId())); - OptionItem optionItem4 = optionItemRepository.save(선택지(optionGroup2.getId())); + // then + assertThat(review.getAnswersByType(TextAnswer.class)) + .extracting(TextAnswer::getQuestionId) + .isEmpty(); + } - Section section = sectionRepository.save(항상_보이는_섹션( - List.of(requiredTextQuestion.getId(), optionalTextQuestion.getId(), - requeiredCheckBoxQuestion.getId(), optionalCheckBoxQuestion.getId()))); + @Test + void 필수가_아닌_선택형_질문에_답변이_없으면_매핑하지_않는다() { + // given + ReviewGroup reviewGroup = reviewGroupRepository.save(리뷰_그룹()); + Question question = questionRepository.save(선택형_옵션_질문()); + OptionGroup optionGroup = optionGroupRepository.save(선택지_그룹(question.getId())); + + Section section = sectionRepository.save(항상_보이는_섹션(List.of(question.getId()))); templateRepository.save(템플릿(List.of(section.getId()))); - String textAnswer = "답".repeat(20); - ReviewAnswerRequest requiredTextAnswerRequest = new ReviewAnswerRequest( - requiredTextQuestion.getId(), null, textAnswer - ); - ReviewAnswerRequest optionalTextAnswerRequest = new ReviewAnswerRequest( - optionalTextQuestion.getId(), null, "" - ); - ReviewAnswerRequest requiredCheckBoxAnswerRequest = new ReviewAnswerRequest( - requeiredCheckBoxQuestion.getId(), List.of(optionItem1.getId()), null - ); - ReviewAnswerRequest optionalCheckBoxAnswerRequest = new ReviewAnswerRequest( - optionalCheckBoxQuestion.getId(), List.of(), null - ); - ReviewRegisterRequest reviewRegisterRequest = new ReviewRegisterRequest(reviewGroup.getReviewRequestCode(), - List.of(requiredTextAnswerRequest, optionalTextAnswerRequest, - requiredCheckBoxAnswerRequest, optionalCheckBoxAnswerRequest)); + ReviewAnswerRequest answerRequest = new ReviewAnswerRequest(question.getId(), List.of(), null); + ReviewRegisterRequest reviewRegisterRequest = new ReviewRegisterRequest( + reviewGroup.getReviewRequestCode(), List.of(answerRequest)); // when Review review = reviewMapper.mapToReview(reviewRegisterRequest); // then - assertAll( - () -> assertThat(review.getAnswersByType(TextAnswer.class)) - .extracting(TextAnswer::getQuestionId) - .containsExactly(requiredTextQuestion.getId()), - () -> assertThat(review.getAnswersByType(CheckboxAnswer.class)) - .extracting(CheckboxAnswer::getQuestionId) - .containsExactly(requeiredCheckBoxQuestion.getId()) - ); + assertThat(review.getAnswersByType(CheckboxAnswer.class)) + .extracting(CheckboxAnswer::getQuestionId) + .isEmpty(); } @Test diff --git a/backend/src/test/java/reviewme/review/service/mapper/TextAnswerMapperTest.java b/backend/src/test/java/reviewme/review/service/mapper/TextAnswerMapperTest.java index 841e2d5a3..b7fc960cf 100644 --- a/backend/src/test/java/reviewme/review/service/mapper/TextAnswerMapperTest.java +++ b/backend/src/test/java/reviewme/review/service/mapper/TextAnswerMapperTest.java @@ -1,23 +1,16 @@ package reviewme.review.service.mapper; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import java.util.List; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullSource; +import org.junit.jupiter.params.provider.ValueSource; import reviewme.review.domain.TextAnswer; import reviewme.review.service.dto.request.ReviewAnswerRequest; -import reviewme.review.service.exception.TextAnswerIncludedOptionItemException; class TextAnswerMapperTest { - /* - TODO: Request를 추상화해야 할까요? - 떠오르는 방법은 아래와 같습니다. - 1: static factory method를 사용 -> 걷잡을 수 없어지지 않을까요? - 2: 다른 방식으로 추상화 ? - */ - @Test void 텍스트_답변을_요청으로부터_매핑한다() { // given @@ -31,16 +24,18 @@ class TextAnswerMapperTest { assertThat(actual.getContent()).isEqualTo("text"); } - @Test - void 텍스트_답변_요청에_옵션이_포함되어_있으면_예외를_발생시킨다() { + @ParameterizedTest + @NullSource + @ValueSource(strings = {"", " "}) + void 텍스트_답변이_비어있는_경우_null로_매핑한다(String text) { // given - ReviewAnswerRequest request = new ReviewAnswerRequest(1L, List.of(1L), "text"); + ReviewAnswerRequest request = new ReviewAnswerRequest(1L, null, text); // when TextAnswerMapper mapper = new TextAnswerMapper(); + TextAnswer actual = mapper.mapToAnswer(request); // then - assertThatThrownBy(() -> mapper.mapToAnswer(request)) - .isInstanceOf(TextAnswerIncludedOptionItemException.class); + assertThat(actual).isNull(); } }