diff --git a/howoldareu_clone/build.gradle b/howoldareu_clone/build.gradle index 7248b5c..8c4d63a 100644 --- a/howoldareu_clone/build.gradle +++ b/howoldareu_clone/build.gradle @@ -2,34 +2,50 @@ plugins { id 'java' id 'org.springframework.boot' version '3.2.0' id 'io.spring.dependency-management' version '1.1.4' + id 'org.asciidoctor.convert' version '1.5.8' } group = 'com.sopt' version = '0.0.1-SNAPSHOT' - java { sourceCompatibility = '17' } - configurations { compileOnly { extendsFrom annotationProcessor } } +ext { + set('snippetsDir', file("build/generated-snippets")) +} + repositories { mavenCentral() } - dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' + + // h2 + runtimeOnly 'com.h2database:h2' + annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' + + // Rest Docs + testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc' + testImplementation 'org.springframework.restdocs:spring-restdocs-asciidoctor' } tasks.named('test') { + outputs.dir snippetsDir useJUnitPlatform() } + +tasks.named('asciidoctor') { + inputs.dir snippetsDir + dependsOn test +} \ No newline at end of file diff --git a/howoldareu_clone/src/docs/asciidoc/api/member.adoc b/howoldareu_clone/src/docs/asciidoc/api/member.adoc new file mode 100644 index 0000000..c2265ad --- /dev/null +++ b/howoldareu_clone/src/docs/asciidoc/api/member.adoc @@ -0,0 +1,9 @@ +[[save-member]] +== Save Member + +=== HTTP Request +include::{snippets}/save-member/http-request.adoc[] + +=== HTTP Response +include::{snippets}/save-member/http-response.adoc[] +include::{snippets}/save-member/response-fields.adoc[] \ No newline at end of file diff --git a/howoldareu_clone/src/docs/asciidoc/api/question.adoc b/howoldareu_clone/src/docs/asciidoc/api/question.adoc new file mode 100644 index 0000000..417d514 --- /dev/null +++ b/howoldareu_clone/src/docs/asciidoc/api/question.adoc @@ -0,0 +1,9 @@ +[[get-question]] +== GET Question + +=== HTTP Request +include::{snippets}/get-questions/http-request.adoc[] + +=== HTTP Response +include::{snippets}/get-questions/http-response.adoc[] +include::{snippets}/get-questions/response-fields.adoc[] \ No newline at end of file diff --git a/howoldareu_clone/src/docs/asciidoc/api/result.adoc b/howoldareu_clone/src/docs/asciidoc/api/result.adoc new file mode 100644 index 0000000..03dfd04 --- /dev/null +++ b/howoldareu_clone/src/docs/asciidoc/api/result.adoc @@ -0,0 +1,19 @@ +[[save-result]] +== SAVE RESULT + +=== HTTP Request +include::{snippets}/save-result/http-request.adoc[] + +=== HTTP Response +include::{snippets}/save-result/http-response.adoc[] +include::{snippets}/save-result/response-fields.adoc[] + +[[get-all-results]] +== GET ALL RESULTS + +=== HTTP Request +include::{snippets}/get-all-results/http-request.adoc[] + +=== HTTP Response +include::{snippets}/get-all-results/http-response.adoc[] +include::{snippets}/get-all-results/response-fields.adoc[] \ No newline at end of file diff --git a/howoldareu_clone/src/docs/asciidoc/index.adoc b/howoldareu_clone/src/docs/asciidoc/index.adoc new file mode 100644 index 0000000..40a4f3f --- /dev/null +++ b/howoldareu_clone/src/docs/asciidoc/index.adoc @@ -0,0 +1,23 @@ +ifndef::snippets[] +:snippets: "../../build/generated-snippets" +endif::[] + += HOWOLDAREYOU REST API 문서 +:doctype: book +:icons: font +:source-highlighter: highlightjs +:toc: left +:toclevels: 2 +:seclinks: + +[[Member-API]] +== Member API +include::api/member.adoc[] + +[[Question-API]] +== Question API +include::api/question.adoc[] + +[[Result-API]] +== Result API +include::api/result.adoc[] \ No newline at end of file diff --git a/howoldareu_clone/src/main/java/com/sopt/Server/ServerApplication.java b/howoldareu_clone/src/main/java/com/sopt/Server/ServerApplication.java index 8b1ae1f..24289f4 100644 --- a/howoldareu_clone/src/main/java/com/sopt/Server/ServerApplication.java +++ b/howoldareu_clone/src/main/java/com/sopt/Server/ServerApplication.java @@ -5,7 +5,6 @@ import org.springframework.data.jpa.repository.config.EnableJpaAuditing; @SpringBootApplication -@EnableJpaAuditing public class ServerApplication { public static void main(String[] args) { diff --git a/howoldareu_clone/src/main/java/com/sopt/Server/common/JpaAuditingConfiguration.java b/howoldareu_clone/src/main/java/com/sopt/Server/common/JpaAuditingConfiguration.java new file mode 100644 index 0000000..bda23dc --- /dev/null +++ b/howoldareu_clone/src/main/java/com/sopt/Server/common/JpaAuditingConfiguration.java @@ -0,0 +1,9 @@ +package com.sopt.Server.common; + +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +import org.springframework.stereotype.Component; + +@Component +@EnableJpaAuditing +public class JpaAuditingConfiguration { +} diff --git a/howoldareu_clone/src/main/java/com/sopt/Server/controller/MemberController.java b/howoldareu_clone/src/main/java/com/sopt/Server/controller/MemberController.java index 35d6709..6b87b02 100644 --- a/howoldareu_clone/src/main/java/com/sopt/Server/controller/MemberController.java +++ b/howoldareu_clone/src/main/java/com/sopt/Server/controller/MemberController.java @@ -5,20 +5,25 @@ import com.sopt.Server.controller.response.MemberGetResponse; import com.sopt.Server.service.MemberService; import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; +import java.net.URI; + +import static com.sopt.Server.exception.Success.CREATE_MEMBER_SUCCESS; + @RestController @RequiredArgsConstructor public class MemberController { - + private final MemberService memberService; @PostMapping("/member") - public ApiResponse saveMember(@RequestBody MemberPostRequest request) { - - ApiResponse response = memberService.saveMember(request.nickName(), request.age()); - return response; + public ResponseEntity> saveMember(@RequestBody MemberPostRequest request) { + MemberGetResponse response = memberService.saveMember(request); + URI uri = URI.create("/member"+response.memberId()); + return ResponseEntity.created(uri).body(ApiResponse.success(CREATE_MEMBER_SUCCESS, response)); } } diff --git a/howoldareu_clone/src/main/java/com/sopt/Server/controller/QuestionController.java b/howoldareu_clone/src/main/java/com/sopt/Server/controller/QuestionController.java index 9546e0f..d5019c1 100644 --- a/howoldareu_clone/src/main/java/com/sopt/Server/controller/QuestionController.java +++ b/howoldareu_clone/src/main/java/com/sopt/Server/controller/QuestionController.java @@ -1,7 +1,7 @@ package com.sopt.Server.controller; import com.sopt.Server.common.ApiResponse; -import com.sopt.Server.controller.response.GetQuestionResponseDTO; +import com.sopt.Server.controller.response.GetQuestionResponse; import com.sopt.Server.exception.Success; import com.sopt.Server.service.QuestionService; import lombok.RequiredArgsConstructor; @@ -18,8 +18,8 @@ public class QuestionController { private final QuestionService questionService; @GetMapping("") - public ApiResponse> getQuestionResponseDTOList() { - return ApiResponse.success(Success.GET_QUESTION_LIST_SUCCESS,questionService.getQuestionResponseDTOList()); + public ApiResponse> getQuestionResponseList() { + return ApiResponse.success(Success.GET_QUESTION_LIST_SUCCESS,questionService.getQuestionResponseList()); } } diff --git a/howoldareu_clone/src/main/java/com/sopt/Server/controller/ResultController.java b/howoldareu_clone/src/main/java/com/sopt/Server/controller/ResultController.java index 09b0a45..4f9d4ab 100644 --- a/howoldareu_clone/src/main/java/com/sopt/Server/controller/ResultController.java +++ b/howoldareu_clone/src/main/java/com/sopt/Server/controller/ResultController.java @@ -1,14 +1,16 @@ package com.sopt.Server.controller; import com.sopt.Server.common.ApiResponse; -import com.sopt.Server.controller.request.AnswerListRequestDTO; -import com.sopt.Server.controller.response.AllResultsResponseDTO; -import com.sopt.Server.controller.response.ResultResponseDTO; +import com.sopt.Server.controller.request.AnswerListRequest; +import com.sopt.Server.controller.response.AllResultsResponse; +import com.sopt.Server.controller.response.ResultResponse; import com.sopt.Server.exception.Success; import com.sopt.Server.service.ResultService; import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import java.net.URI; import java.util.List; @RestController @@ -18,12 +20,14 @@ public class ResultController { private final ResultService resultService; @PostMapping("") - public ApiResponse saveResult(@RequestBody AnswerListRequestDTO answerListRequestDTO){ - return ApiResponse.success(Success.CREATE_RESULT_SUCCESS,resultService.saveResult(answerListRequestDTO)); + public ResponseEntity> saveResult(@RequestBody AnswerListRequest answerListRequestDTO){ + ResultResponse response = resultService.saveResult(answerListRequestDTO); + URI uri = URI.create("/result"); + return ResponseEntity.created(uri).body(ApiResponse.success(Success.CREATE_RESULT_SUCCESS,response)); } @GetMapping("/{memberId}") - public ApiResponse> getAllResults(@PathVariable Long memberId) { + public ApiResponse> getAllResults(@PathVariable Long memberId) { return ApiResponse.success(Success.GET_USER_LIST_SUCCESS, resultService.getAllResults(memberId)); } diff --git a/howoldareu_clone/src/main/java/com/sopt/Server/controller/request/AnswerListRequest.java b/howoldareu_clone/src/main/java/com/sopt/Server/controller/request/AnswerListRequest.java new file mode 100644 index 0000000..f41b0f2 --- /dev/null +++ b/howoldareu_clone/src/main/java/com/sopt/Server/controller/request/AnswerListRequest.java @@ -0,0 +1,6 @@ +package com.sopt.Server.controller.request; + +import java.util.List; + +public record AnswerListRequest(String nickname, List results) { +} diff --git a/howoldareu_clone/src/main/java/com/sopt/Server/controller/request/AnswerListRequestDTO.java b/howoldareu_clone/src/main/java/com/sopt/Server/controller/request/AnswerListRequestDTO.java deleted file mode 100644 index 5d78ef6..0000000 --- a/howoldareu_clone/src/main/java/com/sopt/Server/controller/request/AnswerListRequestDTO.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.sopt.Server.controller.request; - -import java.util.List; - -public record AnswerListRequestDTO(String nickname, List results) { -} diff --git a/howoldareu_clone/src/main/java/com/sopt/Server/controller/request/AnswerRequest.java b/howoldareu_clone/src/main/java/com/sopt/Server/controller/request/AnswerRequest.java new file mode 100644 index 0000000..07a40ce --- /dev/null +++ b/howoldareu_clone/src/main/java/com/sopt/Server/controller/request/AnswerRequest.java @@ -0,0 +1,4 @@ +package com.sopt.Server.controller.request; + +public record AnswerRequest(Long questionId, boolean answerType) { +} diff --git a/howoldareu_clone/src/main/java/com/sopt/Server/controller/request/AnswerRequestDTO.java b/howoldareu_clone/src/main/java/com/sopt/Server/controller/request/AnswerRequestDTO.java deleted file mode 100644 index af31390..0000000 --- a/howoldareu_clone/src/main/java/com/sopt/Server/controller/request/AnswerRequestDTO.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.sopt.Server.controller.request; - -public record AnswerRequestDTO(Long questionId, boolean answerType) { -} diff --git a/howoldareu_clone/src/main/java/com/sopt/Server/controller/response/AllResultsResponse.java b/howoldareu_clone/src/main/java/com/sopt/Server/controller/response/AllResultsResponse.java new file mode 100644 index 0000000..b9d7542 --- /dev/null +++ b/howoldareu_clone/src/main/java/com/sopt/Server/controller/response/AllResultsResponse.java @@ -0,0 +1,11 @@ +package com.sopt.Server.controller.response; + +import com.sopt.Server.domain.Result; + +import java.util.List; + +public record AllResultsResponse(Long id, int resultAge, String title, String content, String testedDate, String imgUrl1, String imgUrl2) { + public static AllResultsResponse of(Result result, String title, String content, String testedDate, String imgUrl1, String imgUrl2) { + return new AllResultsResponse(result.getId(), result.getResultAge(), title, content, testedDate, imgUrl1, imgUrl2); + } +} \ No newline at end of file diff --git a/howoldareu_clone/src/main/java/com/sopt/Server/controller/response/AllResultsResponseDTO.java b/howoldareu_clone/src/main/java/com/sopt/Server/controller/response/AllResultsResponseDTO.java deleted file mode 100644 index 052be1e..0000000 --- a/howoldareu_clone/src/main/java/com/sopt/Server/controller/response/AllResultsResponseDTO.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.sopt.Server.controller.response; - -import com.sopt.Server.domain.Result; - -public record AllResultsResponseDTO(Long id, int resultAge, String title, String content, String testedDate, String imgUrl1, String imgUrl2) { - public static AllResultsResponseDTO of(Result result, String title, String content, String testedDate, String imgUrl1, String imgUrl2) { - return new AllResultsResponseDTO(result.getId(), result.getResultAge(), title, content, testedDate, imgUrl1, imgUrl2); - } -} \ No newline at end of file diff --git a/howoldareu_clone/src/main/java/com/sopt/Server/controller/response/GetQuestionResponse.java b/howoldareu_clone/src/main/java/com/sopt/Server/controller/response/GetQuestionResponse.java new file mode 100644 index 0000000..98e11e7 --- /dev/null +++ b/howoldareu_clone/src/main/java/com/sopt/Server/controller/response/GetQuestionResponse.java @@ -0,0 +1,7 @@ +package com.sopt.Server.controller.response; + +public record GetQuestionResponse(Long questionId, String questionContent) { + static public GetQuestionResponse of(Long questionId, String questionContent) { + return new GetQuestionResponse(questionId, questionContent); + } +} diff --git a/howoldareu_clone/src/main/java/com/sopt/Server/controller/response/GetQuestionResponseDTO.java b/howoldareu_clone/src/main/java/com/sopt/Server/controller/response/GetQuestionResponseDTO.java deleted file mode 100644 index 20bbe08..0000000 --- a/howoldareu_clone/src/main/java/com/sopt/Server/controller/response/GetQuestionResponseDTO.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.sopt.Server.controller.response; - -public record GetQuestionResponseDTO(Long questionId, String questionContent) { - static public GetQuestionResponseDTO of(Long questionId, String questionContent) { - return new GetQuestionResponseDTO(questionId, questionContent); - } -} diff --git a/howoldareu_clone/src/main/java/com/sopt/Server/controller/response/ResultResponse.java b/howoldareu_clone/src/main/java/com/sopt/Server/controller/response/ResultResponse.java new file mode 100644 index 0000000..f92ba4a --- /dev/null +++ b/howoldareu_clone/src/main/java/com/sopt/Server/controller/response/ResultResponse.java @@ -0,0 +1,7 @@ +package com.sopt.Server.controller.response; + +public record ResultResponse(String nickname, int resultAge, String title, String content, String imgUrl1, String imgUrl2) { + public static ResultResponse of(String nickname, int resultAge, String title, String content, String imgUrl1, String imgUrl2) { + return new ResultResponse(nickname, resultAge, title, content, imgUrl1, imgUrl2); + } +} diff --git a/howoldareu_clone/src/main/java/com/sopt/Server/controller/response/ResultResponseDTO.java b/howoldareu_clone/src/main/java/com/sopt/Server/controller/response/ResultResponseDTO.java deleted file mode 100644 index f04a849..0000000 --- a/howoldareu_clone/src/main/java/com/sopt/Server/controller/response/ResultResponseDTO.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.sopt.Server.controller.response; - -public record ResultResponseDTO(String nickname, int resultAge, String title, String content, String imgUrl1, String imgUrl2) { - public static ResultResponseDTO of(String nickname, int resultAge, String title, String content, String imgUrl1, String imgUrl2) { - return new ResultResponseDTO(nickname, resultAge, title, content, imgUrl1, imgUrl2); - } -} diff --git a/howoldareu_clone/src/main/java/com/sopt/Server/domain/Answer.java b/howoldareu_clone/src/main/java/com/sopt/Server/domain/Answer.java index 4efbc45..fdfdf9b 100644 --- a/howoldareu_clone/src/main/java/com/sopt/Server/domain/Answer.java +++ b/howoldareu_clone/src/main/java/com/sopt/Server/domain/Answer.java @@ -2,6 +2,7 @@ import jakarta.persistence.*; import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -14,11 +15,17 @@ public class Answer { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long answerId; - @ManyToOne + @ManyToOne(fetch = FetchType.LAZY) private Question question; private boolean answerType; private int answerScore; + @Builder + public Answer(Question question, boolean answerType, int answerScore) { + this.question = question; + this.answerType = answerType; + this.answerScore = answerScore; + } } diff --git a/howoldareu_clone/src/main/java/com/sopt/Server/domain/Question.java b/howoldareu_clone/src/main/java/com/sopt/Server/domain/Question.java index c1cfd93..eb811f3 100644 --- a/howoldareu_clone/src/main/java/com/sopt/Server/domain/Question.java +++ b/howoldareu_clone/src/main/java/com/sopt/Server/domain/Question.java @@ -1,13 +1,23 @@ package com.sopt.Server.domain; import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; +import lombok.NoArgsConstructor; @Entity @Getter @Table(name = "QUESTIONS") +@NoArgsConstructor(access = AccessLevel.PROTECTED) public class Question { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long questionId; private String questionContent; + + @Builder + public Question(Long questionId, String questionContent) { + this.questionId = questionId; + this.questionContent = questionContent; + } } diff --git a/howoldareu_clone/src/main/java/com/sopt/Server/domain/Result.java b/howoldareu_clone/src/main/java/com/sopt/Server/domain/Result.java index 42752a5..a21a1c4 100644 --- a/howoldareu_clone/src/main/java/com/sopt/Server/domain/Result.java +++ b/howoldareu_clone/src/main/java/com/sopt/Server/domain/Result.java @@ -34,4 +34,8 @@ public Result(Long id, Member member, int resultAge, LocalDateTime testedDate) { this.resultAge = resultAge; this.testedDate = testedDate; } + + public String getTestedDateToString(){ + return testedDate.getMonthValue() + "월 " + testedDate.getDayOfMonth() + "일"; + } } diff --git a/howoldareu_clone/src/main/java/com/sopt/Server/common/AgeEnum.java b/howoldareu_clone/src/main/java/com/sopt/Server/domain/enums/AgeEnum.java similarity index 84% rename from howoldareu_clone/src/main/java/com/sopt/Server/common/AgeEnum.java rename to howoldareu_clone/src/main/java/com/sopt/Server/domain/enums/AgeEnum.java index c48727c..3d62a69 100644 --- a/howoldareu_clone/src/main/java/com/sopt/Server/common/AgeEnum.java +++ b/howoldareu_clone/src/main/java/com/sopt/Server/domain/enums/AgeEnum.java @@ -1,4 +1,4 @@ -package com.sopt.Server.common; +package com.sopt.Server.domain.enums; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -18,5 +18,18 @@ public enum AgeEnum { private final String imageUrl1; private final String imageUrl2; + public static AgeEnum getAgeEnum(int age){ + if(age < 20) + return AgeEnum.TEENAGER; + else if(age < 30) + return AgeEnum.TWENTIES; + else if(age < 40) + return AgeEnum.THIRTIES; + else if(age < 50) + return AgeEnum.FORTIES; + else + return AgeEnum.FIFTIES; + } + } diff --git a/howoldareu_clone/src/main/java/com/sopt/Server/repository/MemberJpaRepository.java b/howoldareu_clone/src/main/java/com/sopt/Server/repository/MemberJpaRepository.java index e9259dd..05406ae 100644 --- a/howoldareu_clone/src/main/java/com/sopt/Server/repository/MemberJpaRepository.java +++ b/howoldareu_clone/src/main/java/com/sopt/Server/repository/MemberJpaRepository.java @@ -1,10 +1,19 @@ package com.sopt.Server.repository; import com.sopt.Server.domain.Member; +import com.sopt.Server.exception.model.CustomException; +import jakarta.persistence.EntityNotFoundException; import org.springframework.data.jpa.repository.JpaRepository; import java.util.Optional; +import static com.sopt.Server.exception.Error.NOT_FOUND_MEMBER_EXCEPTION; + public interface MemberJpaRepository extends JpaRepository { Optional findByName(String name); + default Member findByNameOrThrow(String name) { + return findByName(name) + .orElseThrow(() -> + new CustomException(NOT_FOUND_MEMBER_EXCEPTION, NOT_FOUND_MEMBER_EXCEPTION.getMessage())); + } } diff --git a/howoldareu_clone/src/main/java/com/sopt/Server/repository/QuestionJpaRepository.java b/howoldareu_clone/src/main/java/com/sopt/Server/repository/QuestionJpaRepository.java index 56d6621..e70cdb2 100644 --- a/howoldareu_clone/src/main/java/com/sopt/Server/repository/QuestionJpaRepository.java +++ b/howoldareu_clone/src/main/java/com/sopt/Server/repository/QuestionJpaRepository.java @@ -7,6 +7,4 @@ import java.util.Optional; public interface QuestionJpaRepository extends JpaRepository{ - List findAll(); - Optional findById(Long id); } diff --git a/howoldareu_clone/src/main/java/com/sopt/Server/repository/ResultJpaRepository.java b/howoldareu_clone/src/main/java/com/sopt/Server/repository/ResultJpaRepository.java index e9cb02b..67d7279 100644 --- a/howoldareu_clone/src/main/java/com/sopt/Server/repository/ResultJpaRepository.java +++ b/howoldareu_clone/src/main/java/com/sopt/Server/repository/ResultJpaRepository.java @@ -6,7 +6,5 @@ import java.util.List; public interface ResultJpaRepository extends JpaRepository{ - Result save(Result result); - List findAllByMemberIdOrderByIdDesc(Long memberId); } diff --git a/howoldareu_clone/src/main/java/com/sopt/Server/service/MemberService.java b/howoldareu_clone/src/main/java/com/sopt/Server/service/MemberService.java index b61f781..b6c954a 100644 --- a/howoldareu_clone/src/main/java/com/sopt/Server/service/MemberService.java +++ b/howoldareu_clone/src/main/java/com/sopt/Server/service/MemberService.java @@ -1,16 +1,14 @@ package com.sopt.Server.service; -import com.sopt.Server.common.ApiResponse; +import com.sopt.Server.controller.request.MemberPostRequest; import com.sopt.Server.controller.response.MemberGetResponse; import com.sopt.Server.domain.Member; -import com.sopt.Server.exception.Success; import com.sopt.Server.repository.MemberJpaRepository; +import jakarta.persistence.EntityNotFoundException; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Optional; - @Service @RequiredArgsConstructor @Transactional(readOnly = true) @@ -19,14 +17,17 @@ public class MemberService { private final MemberJpaRepository memberJpaRepository; @Transactional - public ApiResponse saveMember(String nickName, int age) { - Member newMember = Member.builder().name(nickName).realAge(age).build(); - Member member = memberJpaRepository.findByName(nickName).orElse(null);//null이면 - if(member != null)//있다면 - return ApiResponse.success(Success.GET_MEMBER_SUCCESS, MemberGetResponse.of(member)); - else { + public MemberGetResponse saveMember(MemberPostRequest request) { + try { + Member member = memberJpaRepository.findByNameOrThrow(request.nickName()); + return MemberGetResponse.of(member); + } catch (EntityNotFoundException e) { + Member newMember = Member.builder() + .name(request.nickName()) + .realAge(request.age()) + .build(); memberJpaRepository.save(newMember); + return MemberGetResponse.of(newMember); } - return ApiResponse.success(Success.CREATE_MEMBER_SUCCESS, MemberGetResponse.of(newMember)); } } diff --git a/howoldareu_clone/src/main/java/com/sopt/Server/service/QuestionService.java b/howoldareu_clone/src/main/java/com/sopt/Server/service/QuestionService.java index 5405e37..482578b 100644 --- a/howoldareu_clone/src/main/java/com/sopt/Server/service/QuestionService.java +++ b/howoldareu_clone/src/main/java/com/sopt/Server/service/QuestionService.java @@ -1,6 +1,6 @@ package com.sopt.Server.service; -import com.sopt.Server.controller.response.GetQuestionResponseDTO; +import com.sopt.Server.controller.response.GetQuestionResponse; import com.sopt.Server.domain.Question; import com.sopt.Server.repository.QuestionJpaRepository; import lombok.RequiredArgsConstructor; @@ -16,13 +16,13 @@ public class QuestionService { private final QuestionJpaRepository questionJpaRepository; - public List getQuestionResponseDTOList() { + public List getQuestionResponseList() { List questionList = questionJpaRepository.findAll(); - List getQuestionResponseDTOList = new ArrayList<>(); + List getQuestionResponseList = new ArrayList<>(); for(Question question : questionList){ - getQuestionResponseDTOList.add(GetQuestionResponseDTO.of(question.getQuestionId(),question.getQuestionContent())); + getQuestionResponseList.add(GetQuestionResponse.of(question.getQuestionId(),question.getQuestionContent())); } - return getQuestionResponseDTOList; + return getQuestionResponseList; } } diff --git a/howoldareu_clone/src/main/java/com/sopt/Server/service/ResultService.java b/howoldareu_clone/src/main/java/com/sopt/Server/service/ResultService.java index 5a24a8d..42b7a55 100644 --- a/howoldareu_clone/src/main/java/com/sopt/Server/service/ResultService.java +++ b/howoldareu_clone/src/main/java/com/sopt/Server/service/ResultService.java @@ -1,10 +1,10 @@ package com.sopt.Server.service; -import com.sopt.Server.common.AgeEnum; -import com.sopt.Server.controller.request.AnswerListRequestDTO; -import com.sopt.Server.controller.request.AnswerRequestDTO; -import com.sopt.Server.controller.response.AllResultsResponseDTO; -import com.sopt.Server.controller.response.ResultResponseDTO; +import com.sopt.Server.domain.enums.AgeEnum; +import com.sopt.Server.controller.request.AnswerListRequest; +import com.sopt.Server.controller.request.AnswerRequest; +import com.sopt.Server.controller.response.AllResultsResponse; +import com.sopt.Server.controller.response.ResultResponse; import com.sopt.Server.domain.Answer; import com.sopt.Server.domain.Member; import com.sopt.Server.domain.Question; @@ -19,7 +19,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @@ -33,28 +32,28 @@ public class ResultService { private final QuestionJpaRepository questionJpaRepository; @Transactional - public ResultResponseDTO saveResult(AnswerListRequestDTO request) { + public ResultResponse saveResult(AnswerListRequest request) { Member member = memberJpaRepository.findByName(request.nickname()).orElseThrow(()->new CustomException(Error.NOT_FOUND_MEMBER_EXCEPTION,Error.NOT_FOUND_MEMBER_EXCEPTION.getMessage())); int memberAge = member.getRealAge(); - for(AnswerRequestDTO result : request.results()){ + for(AnswerRequest result : request.results()){ Question question = questionJpaRepository.findById(result.questionId()).orElseThrow(()->new CustomException(Error.NOT_FOUND_QUESTION_EXCEPTION,Error.NOT_FOUND_QUESTION_EXCEPTION.getMessage())); Answer answer = answerJpaRepository.findByQuestionAndAnswerType(question, result.answerType()).orElseThrow(()->new CustomException(Error.NOT_FOUND_ANSWER_EXCEPTION,Error.NOT_FOUND_ANSWER_EXCEPTION.getMessage())); memberAge += answer.getAnswerScore(); } - AgeEnum ageEnum = getAgeEnum(memberAge); + AgeEnum ageEnum = AgeEnum.getAgeEnum(memberAge); resultJpaRepository.save(Result.builder().member(member).resultAge(memberAge).build()); - return ResultResponseDTO.of(request.nickname(),memberAge,ageEnum.getTitle(),ageEnum.getContent(),ageEnum.getImageUrl1(), ageEnum.getImageUrl2()); + return ResultResponse.of(request.nickname(),memberAge,ageEnum.getTitle(),ageEnum.getContent(),ageEnum.getImageUrl1(), ageEnum.getImageUrl2()); } - public List getAllResults(Long memberId) { + public List getAllResults(Long memberId) { List resultList = resultJpaRepository.findAllByMemberIdOrderByIdDesc(memberId); - List answer = new ArrayList<>(); - //멤버의 result 모두 갖고옴 이것을 각각의 result마다 allresultsresponsedto만들어야 해 + List answer = new ArrayList<>(); + for(Result result : resultList) { - AgeEnum ageEnum = getAgeEnum(result.getResultAge()); - String time = getStringDate(result.getTestedDate()); - AllResultsResponseDTO dto = AllResultsResponseDTO.of(result, ageEnum.getTitle(), ageEnum.getContent(), time, ageEnum.getImageUrl1(), ageEnum.getImageUrl2()); + AgeEnum ageEnum = AgeEnum.getAgeEnum(result.getResultAge()); + String time = result.getTestedDateToString(); + AllResultsResponse dto = AllResultsResponse.of(result, ageEnum.getTitle(), ageEnum.getContent(), time, ageEnum.getImageUrl1(), ageEnum.getImageUrl2()); answer.add(dto); } @@ -62,22 +61,4 @@ public List getAllResults(Long memberId) { } - private String getStringDate(LocalDateTime time) { - String answer = time.getMonthValue() + "월 " + time.getDayOfMonth() + "일"; - return answer; - } - - private AgeEnum getAgeEnum(int age){ - if(age < 20) - return AgeEnum.TEENAGER; - else if(age < 30) - return AgeEnum.TWENTIES; - else if(age < 40) - return AgeEnum.THIRTIES; - else if(age < 50) - return AgeEnum.FORTIES; - else - return AgeEnum.FIFTIES; - } - } diff --git a/howoldareu_clone/src/test/java/com/sopt/Server/controller/MemberControllerTest.java b/howoldareu_clone/src/test/java/com/sopt/Server/controller/MemberControllerTest.java new file mode 100644 index 0000000..8fc8ede --- /dev/null +++ b/howoldareu_clone/src/test/java/com/sopt/Server/controller/MemberControllerTest.java @@ -0,0 +1,61 @@ +package com.sopt.Server.controller; + +import com.sopt.Server.controller.request.MemberPostRequest; +import com.sopt.Server.controller.response.MemberGetResponse; +import com.sopt.Server.service.MemberService; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.BDDMockito; +import org.springframework.restdocs.payload.JsonFieldType; +import org.springframework.test.web.servlet.ResultActions; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.payload.PayloadDocumentation.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +class MemberControllerTest extends RestDocsSupport { + private final MemberService memberService = mock(MemberService.class); + private static final String MEMBER_POST_URL = "/member"; + + @Override + protected Object initializeController() { + return new MemberController(memberService); + } + + @Test + @DisplayName("사용자를 등록한다") + void saveMemberTest() throws Exception { + // given + MemberGetResponse response = new MemberGetResponse(1L, "euna", 24); + BDDMockito.given(memberService.saveMember(any(MemberPostRequest.class))).willReturn(response); + MemberPostRequest request = new MemberPostRequest("euna", 24); + + // when + ResultActions result = mockMvc.perform(post(MEMBER_POST_URL) + .content(objectMapper.writeValueAsString(request)) + .contentType(json) + .accept(json) + ); + + //then + result.andExpect(status().isCreated()) + .andDo(print()) + .andDo(document("save-member", + requestFields( + fieldWithPath("nickName").type(JsonFieldType.STRING).description("회원 닉네임"), + fieldWithPath("age").type(JsonFieldType.NUMBER).description("회원 나이") + ), + responseFields( + fieldWithPath("code").type(JsonFieldType.NUMBER).description("응답 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지"), + fieldWithPath("data.memberId").type(JsonFieldType.NUMBER).description("회원 식별자"), + fieldWithPath("data.nickName").type(JsonFieldType.STRING).description("회원 닉네임"), + fieldWithPath("data.realAge").type(JsonFieldType.NUMBER).description("회원 나이") + ) + )); + } +} \ No newline at end of file diff --git a/howoldareu_clone/src/test/java/com/sopt/Server/controller/QuestionControllerTest.java b/howoldareu_clone/src/test/java/com/sopt/Server/controller/QuestionControllerTest.java new file mode 100644 index 0000000..549439c --- /dev/null +++ b/howoldareu_clone/src/test/java/com/sopt/Server/controller/QuestionControllerTest.java @@ -0,0 +1,58 @@ +package com.sopt.Server.controller; + +import com.sopt.Server.controller.response.GetQuestionResponse; +import com.sopt.Server.service.QuestionService; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.BDDMockito; +import org.springframework.restdocs.payload.JsonFieldType; +import org.springframework.test.web.servlet.ResultActions; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +public class QuestionControllerTest extends RestDocsSupport{ + private final QuestionService questionService = mock(QuestionService.class); + private final static String QUESTION_GET_URL = "/question"; + + @Override + protected Object initializeController() { + return new QuestionController(questionService); + } + + @Test + @DisplayName("질문 목록을 조회한다") + void getQuestionResponseListTest() throws Exception { + // given + List responseList = List.of( + new GetQuestionResponse(1L, "인생이 부질없다고 생각해본 적 있어?"), + new GetQuestionResponse(2L, "술먹다가 첫차타고 집간적 있어?")); + BDDMockito.given(questionService.getQuestionResponseList()) + .willReturn(responseList); + + // when + ResultActions result = mockMvc.perform(get(QUESTION_GET_URL)); + + //then + result.andExpect(status().isOk()) + .andDo(print()) + .andDo(document("get-questions", + responseFields( + fieldWithPath("code").type(JsonFieldType.NUMBER).description("응답 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지"), + fieldWithPath("data[].questionId").type(JsonFieldType.NUMBER).description("질문 식별자"), + fieldWithPath("data[].questionContent").type(JsonFieldType.STRING).description("질문 내용") + ) + )); + } + + +} \ No newline at end of file diff --git a/howoldareu_clone/src/test/java/com/sopt/Server/controller/RestDocsSupport.java b/howoldareu_clone/src/test/java/com/sopt/Server/controller/RestDocsSupport.java new file mode 100644 index 0000000..b555796 --- /dev/null +++ b/howoldareu_clone/src/test/java/com/sopt/Server/controller/RestDocsSupport.java @@ -0,0 +1,29 @@ +package com.sopt.Server.controller; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.restdocs.RestDocumentationContextProvider; +import org.springframework.restdocs.RestDocumentationExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; + +@ExtendWith(RestDocumentationExtension.class) +public abstract class RestDocsSupport { + + protected MockMvc mockMvc; + protected ObjectMapper objectMapper = new ObjectMapper(); + protected static final String json = "application/json"; + + @BeforeEach + void setUp(RestDocumentationContextProvider provider) { + this.mockMvc = MockMvcBuilders + .standaloneSetup(initializeController()) + .apply(documentationConfiguration(provider)) + .build(); + } + + protected abstract Object initializeController(); +} diff --git a/howoldareu_clone/src/test/java/com/sopt/Server/controller/ResultControllerTest.java b/howoldareu_clone/src/test/java/com/sopt/Server/controller/ResultControllerTest.java new file mode 100644 index 0000000..f56e167 --- /dev/null +++ b/howoldareu_clone/src/test/java/com/sopt/Server/controller/ResultControllerTest.java @@ -0,0 +1,140 @@ +package com.sopt.Server.controller; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.sopt.Server.controller.request.AnswerListRequest; +import com.sopt.Server.controller.request.AnswerRequest; +import com.sopt.Server.controller.response.AllResultsResponse; +import com.sopt.Server.controller.response.ResultResponse; +import com.sopt.Server.domain.Member; +import com.sopt.Server.domain.Result; +import com.sopt.Server.service.ResultService; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.BDDMockito; +import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders; +import org.springframework.restdocs.payload.JsonFieldType; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + +import java.util.List; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.payload.PayloadDocumentation.*; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +public class ResultControllerTest extends RestDocsSupport{ + private final ResultService resultService = mock(ResultService.class); + private final static String RESULT_POST_URL = "/result"; + private final static String RESULTS_GET_URL = "/result/{memberId}"; + private final static Long memberId = 1L; + + @Override + protected Object initializeController() { + return new ResultController(resultService); + } + + @Test + @DisplayName("문답 결과를 저장한다") + void saveResultTest() throws Exception { + // given + ResultResponse response = new ResultResponse("euna", 20, "성장중인 새싹이", "매일 매일 자라고 있는 당신! 다음 달엔 얼마나 발전했을지 궁금한 걸?", "img1", "img2"); + BDDMockito.given(resultService.saveResult(any(AnswerListRequest.class))) + .willReturn(response); + AnswerListRequest request = new AnswerListRequest("euna", List.of(new AnswerRequest(1L, true), + new AnswerRequest(2L, false), + new AnswerRequest(3L, true))); + + // when + ResultActions result = mockMvc.perform(post(RESULT_POST_URL) + .content(objectMapper.writeValueAsString(request)) + .contentType(json) + .accept(json) + ); + + // then + result.andExpect(status().isCreated()) + .andDo(print()) + .andDo(document("save-result", + requestFields( + fieldWithPath("nickname").type(JsonFieldType.STRING).description("회원 닉네임"), + fieldWithPath("results").type(JsonFieldType.ARRAY).description("회원 답변 결과"), + fieldWithPath("results[].questionId").type(JsonFieldType.NUMBER).description("질문 id"), + fieldWithPath("results[].answerType").type(JsonFieldType.BOOLEAN).description("질문에 대한 답변 결과") + ), + responseFields( + fieldWithPath("code").type(JsonFieldType.NUMBER).description("응답 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지"), + fieldWithPath("data.nickname").type(JsonFieldType.STRING).description("회원 식별자"), + fieldWithPath("data.resultAge").type(JsonFieldType.NUMBER).description("결과에 따른 회원 나이"), + fieldWithPath("data.title").type(JsonFieldType.STRING).description("검사 결과 제목"), + fieldWithPath("data.content").type(JsonFieldType.STRING).description("검사 결과 설명"), + fieldWithPath("data.imgUrl1").type(JsonFieldType.STRING).description("검사 결과 카드 앞면 사진"), + fieldWithPath("data.imgUrl2").type(JsonFieldType.STRING).description("검사 결과 카드 뒷면 사진") + ) + )); + } + + @Test + @DisplayName("모든 문답 결과를 조회한다") + void getAllResultsTest() throws Exception { + // given + Member member = new Member("euna", 24); + List response = List.of( + AllResultsResponse.of( + Result.builder() + .id(1L) + .member(member) + .resultAge(20) + .build(), + "성장중인 새싹이", + "매일 매일 자라고 있는 당신! 다음 달엔 얼마나 발전했을지 궁금한 걸?", + "2021년 10월 10일", + "img2", + "img2"), + AllResultsResponse.of( + Result.builder() + .id(2L) + .member(member) + .resultAge(20) + .build(), + "성장중인 새싹이", + "매일 매일 자라고 있는 당신! 다음 달엔 얼마나 발전했을지 궁금한 걸?", + "2021년 10월 10일", + "img2", + "img2") + ); + + BDDMockito.given(resultService.getAllResults(1L)) + .willReturn(response); + + // when: pathParameters를 사용할거면 MockMvcBuilders 보다 RestDocumentationRequestBuilders를 이용하는 것이 좋다. + ResultActions result = mockMvc.perform(RestDocumentationRequestBuilders.get(RESULTS_GET_URL, memberId)); + + // then + result.andExpect(status().isOk()) + .andDo(print()) + .andDo(document("get-all-results", + pathParameters( + parameterWithName("memberId").description("회원 식별자") + ), + responseFields( + fieldWithPath("code").type(JsonFieldType.NUMBER).description("응답 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답 메시지"), + fieldWithPath("data[].id").type(JsonFieldType.NUMBER).description("결과 식별자"), + fieldWithPath("data[].resultAge").type(JsonFieldType.NUMBER).description("결과에 따른 회원 나이"), + fieldWithPath("data[].title").type(JsonFieldType.STRING).description("검사 결과 제목"), + fieldWithPath("data[].content").type(JsonFieldType.STRING).description("검사 결과 설명"), + fieldWithPath("data[].testedDate").type(JsonFieldType.STRING).description("검사 날짜"), + fieldWithPath("data[].imgUrl1").type(JsonFieldType.STRING).description("검사 결과 카드 앞면 사진"), + fieldWithPath("data[].imgUrl2").type(JsonFieldType.STRING).description("검사 결과 카드 뒷면 사진") + ) + )); + } +} \ No newline at end of file diff --git a/howoldareu_clone/src/test/java/com/sopt/Server/domain/ResultTest.java b/howoldareu_clone/src/test/java/com/sopt/Server/domain/ResultTest.java new file mode 100644 index 0000000..68d2591 --- /dev/null +++ b/howoldareu_clone/src/test/java/com/sopt/Server/domain/ResultTest.java @@ -0,0 +1,27 @@ +package com.sopt.Server.domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.time.LocalDateTime; + +import static org.junit.jupiter.api.Assertions.*; + +public class ResultTest { + @Test + @DisplayName("결과가 생성된 일자 정보를 반환한다") + void getTestDateToString() { + // given + LocalDateTime testedDate = LocalDateTime.of(2023, 3, 21, 12, 30); + Result result = Result.builder() + .testedDate(testedDate) + .build(); + String expected = "3월 21일"; + + // when + String resultString = result.getTestedDateToString(); + + // then + assertEquals(expected, resultString); + } +} \ No newline at end of file diff --git a/howoldareu_clone/src/test/java/com/sopt/Server/domain/enums/AgeEnumTest.java b/howoldareu_clone/src/test/java/com/sopt/Server/domain/enums/AgeEnumTest.java new file mode 100644 index 0000000..f38effb --- /dev/null +++ b/howoldareu_clone/src/test/java/com/sopt/Server/domain/enums/AgeEnumTest.java @@ -0,0 +1,34 @@ +package com.sopt.Server.domain.enums; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class AgeEnumTest { + private static final int NINETEEN = 19; + private static final int TWENTY_ONE = 21; + private static final int TWENTY_NINE = 29; + private static final int THIRTY_ONE = 31; + private static final int THIRTY_NINE = 39; + private static final int FORTY_ONE = 41; + private static final int FORTY_NINE = 49; + private static final int FIFTY_ONE = 51; + + + @Test + @DisplayName("연령대로 원하는 정보를 가져올 수 있다.") + void getAgeEnum() { + // then + Assertions.assertThat(AgeEnum.getAgeEnum(NINETEEN)).isEqualTo(AgeEnum.TEENAGER); + Assertions.assertThat(AgeEnum.getAgeEnum(TWENTY_ONE)).isEqualTo(AgeEnum.TWENTIES); + Assertions.assertThat(AgeEnum.getAgeEnum(TWENTY_NINE)).isEqualTo(AgeEnum.TWENTIES); + Assertions.assertThat(AgeEnum.getAgeEnum(THIRTY_ONE)).isEqualTo(AgeEnum.THIRTIES); + Assertions.assertThat(AgeEnum.getAgeEnum(THIRTY_NINE)).isEqualTo(AgeEnum.THIRTIES); + Assertions.assertThat(AgeEnum.getAgeEnum(FORTY_ONE)).isEqualTo(AgeEnum.FORTIES); + Assertions.assertThat(AgeEnum.getAgeEnum(FORTY_NINE)).isEqualTo(AgeEnum.FORTIES); + Assertions.assertThat(AgeEnum.getAgeEnum(FIFTY_ONE)).isEqualTo(AgeEnum.FIFTIES); + } + +} \ No newline at end of file diff --git a/howoldareu_clone/src/test/java/com/sopt/Server/repository/AnswerJpaRepositoryTest.java b/howoldareu_clone/src/test/java/com/sopt/Server/repository/AnswerJpaRepositoryTest.java new file mode 100644 index 0000000..3979e98 --- /dev/null +++ b/howoldareu_clone/src/test/java/com/sopt/Server/repository/AnswerJpaRepositoryTest.java @@ -0,0 +1,43 @@ +package com.sopt.Server.repository; + +import com.sopt.Server.domain.Answer; +import com.sopt.Server.domain.Question; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.test.context.ActiveProfiles; + +import static org.junit.jupiter.api.Assertions.*; + +@DataJpaTest +@ActiveProfiles("test") +class AnswerJpaRepositoryTest { + @Autowired + AnswerJpaRepository answerJpaRepository; + + @Autowired + QuestionJpaRepository questionJpaRepository; + + @AfterEach + void tearDown() { + answerJpaRepository.deleteAllInBatch(); + questionJpaRepository.deleteAllInBatch(); + } + + @Test + void findByQuestionAndAnswerTypeTest() { + // given + Question question = Question.builder().questionContent("텐텐 먹어봤어?").build(); + questionJpaRepository.save(question); + answerJpaRepository.save(Answer.builder().question(question).answerType(false).build()); + answerJpaRepository.save(Answer.builder().question(question).answerType(true).build()); + + // when + Answer answer = answerJpaRepository.findByQuestionAndAnswerType(question, true).orElseThrow(); + + // then + assertTrue(answer.isAnswerType()); + assertEquals(question.getQuestionContent(), answer.getQuestion().getQuestionContent()); + } +} \ No newline at end of file diff --git a/howoldareu_clone/src/test/java/com/sopt/Server/repository/MemberJpaRepositoryTest.java b/howoldareu_clone/src/test/java/com/sopt/Server/repository/MemberJpaRepositoryTest.java new file mode 100644 index 0000000..29cabad --- /dev/null +++ b/howoldareu_clone/src/test/java/com/sopt/Server/repository/MemberJpaRepositoryTest.java @@ -0,0 +1,86 @@ +package com.sopt.Server.repository; + +import com.sopt.Server.domain.Member; +import com.sopt.Server.exception.model.CustomException; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.AfterEach; +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.orm.jpa.DataJpaTest; +import org.springframework.test.context.ActiveProfiles; + +import java.util.Optional; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; + +@DataJpaTest +@ActiveProfiles("test") +class MemberJpaRepositoryTest { + + @Autowired + MemberJpaRepository memberJpaRepository; + + @AfterEach + void tearDown() { + memberJpaRepository.deleteAllInBatch(); + } + + @Test + @DisplayName("이름으로 회원을 조회할 수 있다.") + void findByNameTest() { + + // given + Member member = Member.builder() + .name("euna") + .realAge(24) + .build(); + memberJpaRepository.save(member); + + // when + Optional findMember = memberJpaRepository.findByName("euna"); + + // then + findMember.ifPresent(m -> + Assertions.assertThat(m) + .extracting("name", "realAge") + .containsExactly("euna", 24) + ); + + } + + + @Test + @DisplayName("이름으로 회원을 조회할 수 있다.") + void findByNameOrThrowSuccessTest() { + // given + Member member = Member.builder() + .name("euna") + .realAge(24) + .build(); + memberJpaRepository.save(member); + + // when + Member findMember = memberJpaRepository.findByNameOrThrow("euna"); + + // then + Assertions.assertThat(findMember) + .extracting("name", "realAge") + .containsExactly("euna", 24); + } + + @Test + @DisplayName("이름으로 회원을 조회할 수 없으면 예외가 발생한다.") + void findByNameOrThrowFailTest() { + // given, when, then + assertThatThrownBy(() -> memberJpaRepository.findByNameOrThrow("euna")) + .isInstanceOf(CustomException.class) + .hasMessage("해당 회원을 찾을 수 없습니다"); + } + + /** + * memberJpaRepository.findByNameOrThrow에서 import jakarta.persistence.EntityNotFoundException;를 던지면, + * 실제로는 org.springframework.orm.jpa.JpaObjectRetrievalFailureException가 인식되어 테스트가 실패한다... + * 그렇다면 custom Exception이 최선일까? + **/ +} \ No newline at end of file diff --git a/howoldareu_clone/src/test/java/com/sopt/Server/repository/ResultJpaRepositoryTest.java b/howoldareu_clone/src/test/java/com/sopt/Server/repository/ResultJpaRepositoryTest.java new file mode 100644 index 0000000..dd48023 --- /dev/null +++ b/howoldareu_clone/src/test/java/com/sopt/Server/repository/ResultJpaRepositoryTest.java @@ -0,0 +1,54 @@ +package com.sopt.Server.repository; + +import com.sopt.Server.domain.Member; +import com.sopt.Server.domain.Result; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.test.context.ActiveProfiles; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +@DataJpaTest +@ActiveProfiles("test") +class ResultJpaRepositoryTest { + @Autowired + ResultJpaRepository resultJpaRepository; + + @Autowired + MemberJpaRepository memberJpaRepository; + + @AfterEach + void tearDown() { + resultJpaRepository.deleteAllInBatch(); + memberJpaRepository.deleteAllInBatch(); + } + + @Test + void findAllByMemberIdOrderByIdDesc() { + // given + Member member = Member.builder().name("euna").realAge(24).build(); + memberJpaRepository.save(member); + resultJpaRepository.save(saveResult(member, 24)); + resultJpaRepository.save(saveResult(member, 26)); + + // when + List results = resultJpaRepository.findAllByMemberIdOrderByIdDesc(member.getId()); + + // then + assertNotNull(results); + assertEquals(2, results.size()); + assertEquals(26, results.get(0).getResultAge()); + assertEquals(24, results.get(1).getResultAge()); + + + + } + + private Result saveResult(Member member, int resultAge) { + return Result.builder().member(member).resultAge(resultAge).build(); + } +} \ No newline at end of file diff --git a/howoldareu_clone/src/test/java/com/sopt/Server/service/MemberServiceTest.java b/howoldareu_clone/src/test/java/com/sopt/Server/service/MemberServiceTest.java new file mode 100644 index 0000000..f8170b2 --- /dev/null +++ b/howoldareu_clone/src/test/java/com/sopt/Server/service/MemberServiceTest.java @@ -0,0 +1,47 @@ +package com.sopt.Server.service; + +import com.sopt.Server.controller.request.MemberPostRequest; +import com.sopt.Server.controller.response.MemberGetResponse; +import com.sopt.Server.domain.Member; +import com.sopt.Server.repository.MemberJpaRepository; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.BDDMockito; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.boot.test.context.SpringBootTest; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; + +@SpringBootTest +class MemberServiceTest { + @Mock + MemberJpaRepository memberJpaRepository; + + @InjectMocks + MemberService memberService; + + @Test + @DisplayName("회원을 등록할 수 있다") + void saveMemberTest() { + // given + Member savedMember = Member.builder() + .name("euna") + .realAge(24) + .build(); + BDDMockito.given(memberJpaRepository.findByNameOrThrow(any(String.class))).willReturn(savedMember); + MemberPostRequest request = new MemberPostRequest("euna", 24); + MemberGetResponse mockResponse = MemberGetResponse.of(savedMember); + + // when + MemberGetResponse response = memberService.saveMember(request); + + //then + Assertions.assertThat(response).isEqualTo(mockResponse); + } + + // saveMember의 동작이 두개인데.. 이럴 때는 어떻게 나눠서 테스트해야할까 + // findByNameOrThrow에서 예외가 터지면 save를 동작시킴.. 이런 식일때 +} \ No newline at end of file diff --git a/howoldareu_clone/src/test/java/com/sopt/Server/service/QuestionServiceTest.java b/howoldareu_clone/src/test/java/com/sopt/Server/service/QuestionServiceTest.java new file mode 100644 index 0000000..9c73777 --- /dev/null +++ b/howoldareu_clone/src/test/java/com/sopt/Server/service/QuestionServiceTest.java @@ -0,0 +1,44 @@ +package com.sopt.Server.service; + +import com.sopt.Server.controller.response.GetQuestionResponse; +import com.sopt.Server.domain.Question; +import com.sopt.Server.repository.MemberJpaRepository; +import com.sopt.Server.repository.QuestionJpaRepository; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.BDDMockito; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest +class QuestionServiceTest { + @Mock + QuestionJpaRepository questionJpaRepository; + + @InjectMocks + QuestionService questionService; + + @Test + @DisplayName("질문 리스트 조회 성공") + void getQuestionResponseListTest() { + // given + List questionList = List.of( + Question.builder().questionId(1L).questionContent("텐텐 먹어봤어?").build(), + Question.builder().questionId(2L).questionContent("첫차타고 집에 가봤어?").build()); + BDDMockito.given(questionJpaRepository.findAll()).willReturn(questionList); + List MockResponse = List.of( + GetQuestionResponse.of(1L, "텐텐 먹어봤어?"), + GetQuestionResponse.of(2L, "첫차타고 집에 가봤어?")); + + // when + List response = questionService.getQuestionResponseList(); + + //then + assertEquals(response, MockResponse); + } +} \ No newline at end of file diff --git a/howoldareu_clone/src/test/java/com/sopt/Server/service/ResultServiceTest.java b/howoldareu_clone/src/test/java/com/sopt/Server/service/ResultServiceTest.java new file mode 100644 index 0000000..a0dcf5f --- /dev/null +++ b/howoldareu_clone/src/test/java/com/sopt/Server/service/ResultServiceTest.java @@ -0,0 +1,119 @@ +package com.sopt.Server.service; + +import com.sopt.Server.controller.request.AnswerListRequest; +import com.sopt.Server.controller.request.AnswerRequest; +import com.sopt.Server.controller.response.AllResultsResponse; +import com.sopt.Server.controller.response.ResultResponse; +import com.sopt.Server.domain.Answer; +import com.sopt.Server.domain.Member; +import com.sopt.Server.domain.Question; +import com.sopt.Server.domain.Result; +import com.sopt.Server.exception.model.CustomException; +import com.sopt.Server.repository.AnswerJpaRepository; +import com.sopt.Server.repository.MemberJpaRepository; +import com.sopt.Server.repository.QuestionJpaRepository; +import com.sopt.Server.repository.ResultJpaRepository; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.BDDMockito; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.boot.test.context.SpringBootTest; + +import java.time.LocalDateTime; +import java.time.Month; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; + +@SpringBootTest +class ResultServiceTest { + @Mock + private MemberJpaRepository memberJpaRepository; + + @Mock + private QuestionJpaRepository questionJpaRepository; + + @Mock + private AnswerJpaRepository answerJpaRepository; + + @Mock + private ResultJpaRepository resultJpaRepository; + + @InjectMocks + private ResultService resultService; + + @Test + @DisplayName("결과 저장 성공") + public void saveResultTest_Success() { + // given + AnswerRequest answerRequest1 = new AnswerRequest(1L, true); + AnswerRequest answerRequest2 = new AnswerRequest(2L, false); + AnswerListRequest request = new AnswerListRequest("euna", List.of(answerRequest1, answerRequest2)); + + Member member = Member.builder().name("euna").realAge(24).build(); + Question question1 = Question.builder().build(); + Question question2 = Question.builder().build(); + Answer answer1 = Answer.builder().question(question1).answerType(true).answerScore(2).build(); + Answer answer2 = Answer.builder().question(question2).answerType(false).answerScore(3).build(); + ResultResponse mockResponse = new ResultResponse("euna",29, "말랑한 깜찍이", "뭐가 뭔지 이제 조금 알 것 같은 당신! 앞으로도 재밌는 것들을 많이 알아가보자", + "https://github.com/DO-SOPT-SOPKATHON-iOS4/SOPKATHON-Server/blob/main/image/Frame%2011951.png?raw=true", + "https://github.com/DO-SOPT-SOPKATHON-iOS4/SOPKATHON-Server/blob/main/image/Result_ic_20.png?raw=true"); + + BDDMockito.given(memberJpaRepository.findByName("euna")).willReturn(Optional.of(member)); + BDDMockito.given(questionJpaRepository.findById(1L)).willReturn(Optional.of(question1)); + BDDMockito.given(questionJpaRepository.findById(2L)).willReturn(Optional.of(question2)); + BDDMockito.given(answerJpaRepository.findByQuestionAndAnswerType(question1, true)).willReturn(Optional.of(answer1)); + BDDMockito.given(answerJpaRepository.findByQuestionAndAnswerType(question2, false)).willReturn(Optional.of(answer2)); + + // when + ResultResponse response = resultService.saveResult(request); + + // then + assertThat(response).isEqualTo(mockResponse); + } + + @Test + @DisplayName("결과 저장 실패 - 회원을 찾을 수 없음") + public void saveResultTest_FailMemberNotFound() { + // given + AnswerRequest answerRequest1 = new AnswerRequest(1L, true); + AnswerRequest answerRequest2 = new AnswerRequest(2L, false); + AnswerListRequest request = new AnswerListRequest("nonexistent", List.of(answerRequest1, answerRequest2)); + + BDDMockito.given(memberJpaRepository.findByName("nonexistent")).willReturn(Optional.empty()); + + // when, then + assertThrows(CustomException.class, () -> resultService.saveResult(request)); + } + + @Test + @DisplayName("모든 결과 조회 성공") + public void getAllResultsTest() { + // given + Member member = Member.builder().name("euna").build(); + List resultList = List.of( + Result.builder().id(1L).member(member).resultAge(29).testedDate(LocalDateTime.of(2024, Month.MARCH, 28, 10, 30)).build(), + Result.builder().id(2L).member(member).resultAge(28).testedDate(LocalDateTime.of(2024, Month.MARCH, 28, 10, 30)).build() + ); + BDDMockito.given(resultJpaRepository.findAllByMemberIdOrderByIdDesc(any())).willReturn(resultList); + List mockResponse = List.of( + AllResultsResponse.of(resultList.get(0), "말랑한 깜찍이", "뭐가 뭔지 이제 조금 알 것 같은 당신! 앞으로도 재밌는 것들을 많이 알아가보자", + "3월 28일", + "https://github.com/DO-SOPT-SOPKATHON-iOS4/SOPKATHON-Server/blob/main/image/Frame%2011951.png?raw=true", + "https://github.com/DO-SOPT-SOPKATHON-iOS4/SOPKATHON-Server/blob/main/image/Result_ic_20.png?raw=true"), + AllResultsResponse.of(resultList.get(1), "말랑한 깜찍이", "뭐가 뭔지 이제 조금 알 것 같은 당신! 앞으로도 재밌는 것들을 많이 알아가보자", + "3월 28일", + "https://github.com/DO-SOPT-SOPKATHON-iOS4/SOPKATHON-Server/blob/main/image/Frame%2011951.png?raw=true", + "https://github.com/DO-SOPT-SOPKATHON-iOS4/SOPKATHON-Server/blob/main/image/Result_ic_20.png?raw=true") + ); + // when + List responses = resultService.getAllResults(1L); + + //then + assertThat(responses).isEqualTo(mockResponse); + } +} \ No newline at end of file