From 268afc7a9b4a5a556ab44d67d6248ab715d5480f Mon Sep 17 00:00:00 2001 From: kyeonkim Date: Sun, 23 Feb 2025 16:29:28 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feature:=20=EA=B3=B5=ED=86=B5=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=20=EB=B0=8F=20=EC=9D=91=EB=8B=B5=20=EC=84=A4=EA=B3=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../readup/server/common/dto/ApiResponse.java | 16 +++++++++++++ .../server/common/dto/ErrorResponse.java | 15 ++++++++++++ .../exception/ApplicationException.java | 18 +++++++++++++++ .../common/exception/ControllerException.java | 12 ++++++++++ .../server/common/exception/ErrorCode.java | 23 +++++++++++++++++++ .../common/exception/RepositoryException.java | 12 ++++++++++ .../common/exception/ServiceException.java | 12 ++++++++++ 7 files changed, 108 insertions(+) create mode 100644 src/main/java/com/readup/server/common/dto/ApiResponse.java create mode 100644 src/main/java/com/readup/server/common/dto/ErrorResponse.java create mode 100644 src/main/java/com/readup/server/common/exception/ApplicationException.java create mode 100644 src/main/java/com/readup/server/common/exception/ControllerException.java create mode 100644 src/main/java/com/readup/server/common/exception/ErrorCode.java create mode 100644 src/main/java/com/readup/server/common/exception/RepositoryException.java create mode 100644 src/main/java/com/readup/server/common/exception/ServiceException.java diff --git a/src/main/java/com/readup/server/common/dto/ApiResponse.java b/src/main/java/com/readup/server/common/dto/ApiResponse.java new file mode 100644 index 0000000..e7a7f5a --- /dev/null +++ b/src/main/java/com/readup/server/common/dto/ApiResponse.java @@ -0,0 +1,16 @@ +package com.readup.server.common.dto; + +public record ApiResponse(boolean success, T data, String message) { + + public static ApiResponse success(T data, String message) { + return new ApiResponse<>(true, data, message); + } + + public static ApiResponse success(T data) { + return new ApiResponse<>(true, data, "Request succeeded."); + } + + public static ApiResponse failure(String message) { + return new ApiResponse<>(false, null, message); + } +} diff --git a/src/main/java/com/readup/server/common/dto/ErrorResponse.java b/src/main/java/com/readup/server/common/dto/ErrorResponse.java new file mode 100644 index 0000000..c7cf0bd --- /dev/null +++ b/src/main/java/com/readup/server/common/dto/ErrorResponse.java @@ -0,0 +1,15 @@ +package com.readup.server.common.dto; + +import com.readup.server.common.exception.ErrorCode; + +public record ErrorResponse(int status, String error, String message) { + + public ErrorResponse(ErrorCode errorCode) { + this(errorCode.getHttpStatus().value(), errorCode.name(), errorCode.getMessage()); + } + + public ErrorResponse(ErrorCode errorCode, String customMessage) { + this(errorCode.getHttpStatus().value(), errorCode.name(), customMessage); + + } +} diff --git a/src/main/java/com/readup/server/common/exception/ApplicationException.java b/src/main/java/com/readup/server/common/exception/ApplicationException.java new file mode 100644 index 0000000..073d8ab --- /dev/null +++ b/src/main/java/com/readup/server/common/exception/ApplicationException.java @@ -0,0 +1,18 @@ +package com.readup.server.common.exception; + +import lombok.Getter; + +@Getter +public class ApplicationException extends RuntimeException { + private final ErrorCode errorCode; + + public ApplicationException(ErrorCode errorCode) { + super(errorCode.getMessage()); + this.errorCode = errorCode; + } + + public ApplicationException(ErrorCode errorCode, String customMessage) { + super(customMessage); + this.errorCode = errorCode; + } +} diff --git a/src/main/java/com/readup/server/common/exception/ControllerException.java b/src/main/java/com/readup/server/common/exception/ControllerException.java new file mode 100644 index 0000000..578fdc5 --- /dev/null +++ b/src/main/java/com/readup/server/common/exception/ControllerException.java @@ -0,0 +1,12 @@ +package com.readup.server.common.exception; + +public class ControllerException extends ApplicationException { + + public ControllerException(ErrorCode errorCode) { + super(errorCode); + } + + public ControllerException(ErrorCode errorCode, String customMessage) { + super(errorCode, customMessage); + } +} diff --git a/src/main/java/com/readup/server/common/exception/ErrorCode.java b/src/main/java/com/readup/server/common/exception/ErrorCode.java new file mode 100644 index 0000000..5ce8654 --- /dev/null +++ b/src/main/java/com/readup/server/common/exception/ErrorCode.java @@ -0,0 +1,23 @@ +package com.readup.server.common.exception; + +import org.springframework.http.HttpStatus; + +import lombok.Getter; + +@Getter +public enum ErrorCode { + INVALID_REQUEST(HttpStatus.BAD_REQUEST, "잘못된 요청입니다."), + MISSING_PARAMETER(HttpStatus.BAD_REQUEST, "필수 요청 파라미터가 누락되었습니다."), + RESOURCE_NOT_FOUND(HttpStatus.NOT_FOUND, "요청한 리소스를 찾을 수 없습니다."), + INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "서버 내부 오류가 발생했습니다."), + UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "인증이 필요합니다."), + FORBIDDEN(HttpStatus.FORBIDDEN, "권한이 없습니다."); + + private final HttpStatus httpStatus; + private final String message; + + ErrorCode(HttpStatus httpStatus, String message) { + this.httpStatus = httpStatus; + this.message = message; + } +} diff --git a/src/main/java/com/readup/server/common/exception/RepositoryException.java b/src/main/java/com/readup/server/common/exception/RepositoryException.java new file mode 100644 index 0000000..edb392e --- /dev/null +++ b/src/main/java/com/readup/server/common/exception/RepositoryException.java @@ -0,0 +1,12 @@ +package com.readup.server.common.exception; + +public class RepositoryException extends ApplicationException { + + public RepositoryException(ErrorCode errorCode) { + super(errorCode); + } + + public RepositoryException(ErrorCode errorCode, String customMessage) { + super(errorCode, customMessage); + } +} diff --git a/src/main/java/com/readup/server/common/exception/ServiceException.java b/src/main/java/com/readup/server/common/exception/ServiceException.java new file mode 100644 index 0000000..91f8cd3 --- /dev/null +++ b/src/main/java/com/readup/server/common/exception/ServiceException.java @@ -0,0 +1,12 @@ +package com.readup.server.common.exception; + +public class ServiceException extends ApplicationException { + + public ServiceException(ErrorCode errorCode) { + super(errorCode); + } + + public ServiceException(ErrorCode errorCode, String customMessage) { + super(errorCode, customMessage); + } +} From 8bcebb977ec42617932574940c69634a52ee4f47 Mon Sep 17 00:00:00 2001 From: kyeonkim Date: Sun, 23 Feb 2025 16:44:46 +0900 Subject: [PATCH 2/4] =?UTF-8?q?feature:=20=EA=B3=B5=ED=86=B5=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=20=EC=B2=98=EB=A6=AC=20=ED=95=B8=EB=93=A4=EB=9F=AC=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/GlobalExceptionHandler.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/main/java/com/readup/server/common/exception/GlobalExceptionHandler.java diff --git a/src/main/java/com/readup/server/common/exception/GlobalExceptionHandler.java b/src/main/java/com/readup/server/common/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..db6b57b --- /dev/null +++ b/src/main/java/com/readup/server/common/exception/GlobalExceptionHandler.java @@ -0,0 +1,43 @@ +package com.readup.server.common.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import com.readup.server.common.dto.ErrorResponse; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@RestControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler(ControllerException.class) + public ResponseEntity handleControllerException(ControllerException ex) { + log.error("[ControllerException] {} - {}", ex.getErrorCode(), ex.getMessage()); + ErrorResponse errorResponse = new ErrorResponse(ex.getErrorCode(), ex.getMessage()); + return new ResponseEntity<>(errorResponse, ex.getErrorCode().getHttpStatus()); + } + + @ExceptionHandler(ServiceException.class) + public ResponseEntity handleServiceException(ServiceException ex) { + log.error("[ServiceException] {} - {}", ex.getErrorCode(), ex.getMessage()); + ErrorResponse errorResponse = new ErrorResponse(ex.getErrorCode(), ex.getMessage()); + return new ResponseEntity<>(errorResponse, ex.getErrorCode().getHttpStatus()); + } + + @ExceptionHandler(RepositoryException.class) + public ResponseEntity handleRepositoryException(RepositoryException ex) { + log.error("[RepositoryException] {} - {}", ex.getErrorCode(), ex.getMessage()); + ErrorResponse errorResponse = new ErrorResponse(ex.getErrorCode(), ex.getMessage()); + return new ResponseEntity<>(errorResponse, ex.getErrorCode().getHttpStatus()); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity handleGeneralException(Exception ex) { + log.error("[Unexpected Exception] {} - {}", ex, ex.getMessage()); + ErrorResponse errorResponse = new ErrorResponse(ErrorCode.INTERNAL_SERVER_ERROR); + return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR); + } +} From e2c17c8c7f8ad6b864d8a7446f28e339b9b42bf3 Mon Sep 17 00:00:00 2001 From: kyeonkim Date: Sun, 23 Feb 2025 17:46:28 +0900 Subject: [PATCH 3/4] =?UTF-8?q?feature:=20=EA=B3=B5=ED=86=B5=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=20=EB=B0=8F=20=EC=9D=91=EB=8B=B5=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/integration/ApiResponseTest.java | 31 ++++++++++++ .../controller/TestCommonController.java | 34 +++++++++++++ .../exception/GlobalExceptionHandlerTest.java | 48 +++++++++++++++++++ .../common/unit/CustomExceptionTest.java | 38 +++++++++++++++ 4 files changed, 151 insertions(+) create mode 100644 src/test/java/com/readup/server/common/integration/ApiResponseTest.java create mode 100644 src/test/java/com/readup/server/common/integration/controller/TestCommonController.java create mode 100644 src/test/java/com/readup/server/common/integration/exception/exception/GlobalExceptionHandlerTest.java create mode 100644 src/test/java/com/readup/server/common/unit/CustomExceptionTest.java diff --git a/src/test/java/com/readup/server/common/integration/ApiResponseTest.java b/src/test/java/com/readup/server/common/integration/ApiResponseTest.java new file mode 100644 index 0000000..2d2fa4d --- /dev/null +++ b/src/test/java/com/readup/server/common/integration/ApiResponseTest.java @@ -0,0 +1,31 @@ +package com.readup.server.common.integration; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.test.web.servlet.MockMvc; + +import com.readup.server.common.integration.controller.TestCommonController; + +@WebMvcTest(TestCommonController.class) +@AutoConfigureMockMvc(addFilters = false) +public class ApiResponseTest { + + @Autowired + private MockMvc mockMvc; + + @Test + @DisplayName("정상 응답 반환 테스트") + public void whenNormalEndpointCalled_thenReturnsSuccessResponse() throws Exception { + mockMvc.perform(get("/test/success")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.success").value(true)) + .andExpect(jsonPath("$.data").value("Success Response Data")) + .andExpect(jsonPath("$.message").value("정상 응답입니다.")); + } +} diff --git a/src/test/java/com/readup/server/common/integration/controller/TestCommonController.java b/src/test/java/com/readup/server/common/integration/controller/TestCommonController.java new file mode 100644 index 0000000..e47902d --- /dev/null +++ b/src/test/java/com/readup/server/common/integration/controller/TestCommonController.java @@ -0,0 +1,34 @@ +package com.readup.server.common.integration.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.readup.server.common.dto.ApiResponse; +import com.readup.server.common.exception.ControllerException; +import com.readup.server.common.exception.ErrorCode; +import com.readup.server.common.exception.RepositoryException; +import com.readup.server.common.exception.ServiceException; + +@RestController +public class TestCommonController { + + @GetMapping("/test/controller") + public void throwControllerException() { + throw new ControllerException(ErrorCode.INVALID_REQUEST, "Controller exception occurred"); + } + + @GetMapping("/test/service") + public void throwServiceException() { + throw new ServiceException(ErrorCode.RESOURCE_NOT_FOUND, "Service exception occurred"); + } + + @GetMapping("/test/repository") + public void throwRepositoryException() { + throw new RepositoryException(ErrorCode.INTERNAL_SERVER_ERROR, "Repository exception occurred"); + } + + @GetMapping("/test/success") + public ApiResponse getSuccessResponse() { + return ApiResponse.success("Success Response Data", "정상 응답입니다."); + } +} diff --git a/src/test/java/com/readup/server/common/integration/exception/exception/GlobalExceptionHandlerTest.java b/src/test/java/com/readup/server/common/integration/exception/exception/GlobalExceptionHandlerTest.java new file mode 100644 index 0000000..53d656f --- /dev/null +++ b/src/test/java/com/readup/server/common/integration/exception/exception/GlobalExceptionHandlerTest.java @@ -0,0 +1,48 @@ +package com.readup.server.common.integration.exception.exception; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.test.web.servlet.MockMvc; + +import com.readup.server.common.integration.controller.TestCommonController; + +@WebMvcTest(TestCommonController.class) +@AutoConfigureMockMvc(addFilters = false) +public class GlobalExceptionHandlerTest { + + @Autowired + private MockMvc mockMvc; + + @Test + @DisplayName("컨트롤러 예외 발생 시 올바른 에러 응답 반환") + public void whenControllerExceptionThrown_thenReturnsProperErrorResponse() throws Exception { + mockMvc.perform(get("/test/controller")) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.error").value("INVALID_REQUEST")) + .andExpect(jsonPath("$.message").value("Controller exception occurred")); + } + + @Test + @DisplayName("서비스 예외 발생 시 올바른 에러 응답 반환") + public void whenServiceExceptionThrown_thenReturnsProperErrorResponse() throws Exception { + mockMvc.perform(get("/test/service")) + .andExpect(status().isNotFound()) + .andExpect(jsonPath("$.error").value("RESOURCE_NOT_FOUND")) + .andExpect(jsonPath("$.message").value("Service exception occurred")); + } + + @Test + @DisplayName("레포지토리 예외 발생 시 올바른 에러 응답 반환") + public void whenRepositoryExceptionThrown_thenReturnsProperErrorResponse() throws Exception { + mockMvc.perform(get("/test/repository")) + .andExpect(status().isInternalServerError()) + .andExpect(jsonPath("$.error").value("INTERNAL_SERVER_ERROR")) + .andExpect(jsonPath("$.message").value("Repository exception occurred")); + } +} diff --git a/src/test/java/com/readup/server/common/unit/CustomExceptionTest.java b/src/test/java/com/readup/server/common/unit/CustomExceptionTest.java new file mode 100644 index 0000000..120842d --- /dev/null +++ b/src/test/java/com/readup/server/common/unit/CustomExceptionTest.java @@ -0,0 +1,38 @@ +package com.readup.server.common.unit; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import com.readup.server.common.exception.ControllerException; +import com.readup.server.common.exception.ErrorCode; +import com.readup.server.common.exception.RepositoryException; +import com.readup.server.common.exception.ServiceException; + +public class CustomExceptionTest { + + @Test + @DisplayName("컨트롤러 예외 생성 및 메시지 검증") + public void testControllerException() { + ControllerException ex = new ControllerException(ErrorCode.INVALID_REQUEST, "Test controller error"); + assertEquals(ErrorCode.INVALID_REQUEST, ex.getErrorCode()); + assertEquals("Test controller error", ex.getMessage()); + } + + @Test + @DisplayName("서비스 예외 생성 및 메시지 검증") + public void testServiceException() { + ServiceException ex = new ServiceException(ErrorCode.RESOURCE_NOT_FOUND, "Test service error"); + assertEquals(ErrorCode.RESOURCE_NOT_FOUND, ex.getErrorCode()); + assertEquals("Test service error", ex.getMessage()); + } + + @Test + @DisplayName("레포지토리 예외 생성 및 메시지 검증") + public void testRepositoryException() { + RepositoryException ex = new RepositoryException(ErrorCode.INTERNAL_SERVER_ERROR, "Test repository error"); + assertEquals(ErrorCode.INTERNAL_SERVER_ERROR, ex.getErrorCode()); + assertEquals("Test repository error", ex.getMessage()); + } +} From 1be68b40fbbce26f107c13951564a14034c12b82 Mon Sep 17 00:00:00 2001 From: kyeonkim Date: Mon, 24 Feb 2025 22:19:27 +0900 Subject: [PATCH 4/4] =?UTF-8?q?feature:=20=EA=B3=B5=ED=86=B5=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=20=EB=B0=8F=20=EC=9D=91=EB=8B=B5=20API=20=EB=AC=B8?= =?UTF-8?q?=EC=84=9C=20=EC=9E=90=EB=8F=99=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/docs/asciidoc/common/apiResponse.adoc | 6 ++++ src/docs/asciidoc/common/exception.adoc | 19 ++++++++++++ src/docs/asciidoc/index.adoc | 7 +++++ .../common/integration/ApiResponseTest.java | 23 ++++++++++++++- .../controller/TestCommonController.java | 2 +- .../exception/GlobalExceptionHandlerTest.java | 29 +++++++++++++++++-- 6 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 src/docs/asciidoc/common/apiResponse.adoc create mode 100644 src/docs/asciidoc/common/exception.adoc create mode 100644 src/docs/asciidoc/index.adoc diff --git a/src/docs/asciidoc/common/apiResponse.adoc b/src/docs/asciidoc/common/apiResponse.adoc new file mode 100644 index 0000000..5c3a463 --- /dev/null +++ b/src/docs/asciidoc/common/apiResponse.adoc @@ -0,0 +1,6 @@ +== Successful Response + +include::{snippets}/common/success-response/curl-request.adoc[] +include::{snippets}/common/success-response/http-request.adoc[] +include::{snippets}/common/success-response/http-response.adoc[] +include::{snippets}/common/success-response/response-body.adoc[] diff --git a/src/docs/asciidoc/common/exception.adoc b/src/docs/asciidoc/common/exception.adoc new file mode 100644 index 0000000..b6bb845 --- /dev/null +++ b/src/docs/asciidoc/common/exception.adoc @@ -0,0 +1,19 @@ +== Exception Handling + +=== Controller Exception +include::{snippets}/common/exception/controller-exception/curl-request.adoc[] +include::{snippets}/common/exception/controller-exception/http-request.adoc[] +include::{snippets}/common/exception/controller-exception/http-response.adoc[] +include::{snippets}/common/exception/controller-exception/response-body.adoc[] + +=== Service Exception +include::{snippets}/common/exception/service-exception/curl-request.adoc[] +include::{snippets}/common/exception/service-exception/http-request.adoc[] +include::{snippets}/common/exception/service-exception/http-response.adoc[] +include::{snippets}/common/exception/service-exception/response-body.adoc[] + +=== Repository Exception +include::{snippets}/common/exception/repository-exception/curl-request.adoc[] +include::{snippets}/common/exception/repository-exception/http-request.adoc[] +include::{snippets}/common/exception/repository-exception/http-response.adoc[] +include::{snippets}/common/exception/repository-exception/response-body.adoc[] diff --git a/src/docs/asciidoc/index.adoc b/src/docs/asciidoc/index.adoc new file mode 100644 index 0000000..608b177 --- /dev/null +++ b/src/docs/asciidoc/index.adoc @@ -0,0 +1,7 @@ += ReadUp API Documentation +:toc: left +:toclevels: 3 +:snippets: ../../../../build/generated-snippets + +include::./src/docs/asciidoc/common/apiResponse.adoc[] +include::./src/docs/asciidoc/common/exception.adoc[] diff --git a/src/test/java/com/readup/server/common/integration/ApiResponseTest.java b/src/test/java/com/readup/server/common/integration/ApiResponseTest.java index 2d2fa4d..9478364 100644 --- a/src/test/java/com/readup/server/common/integration/ApiResponseTest.java +++ b/src/test/java/com/readup/server/common/integration/ApiResponseTest.java @@ -1,24 +1,44 @@ package com.readup.server.common.integration; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +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 org.springframework.web.context.WebApplicationContext; import com.readup.server.common.integration.controller.TestCommonController; @WebMvcTest(TestCommonController.class) @AutoConfigureMockMvc(addFilters = false) +@ExtendWith(RestDocumentationExtension.class) +@AutoConfigureRestDocs(outputDir = "build/generated-snippets") public class ApiResponseTest { @Autowired private MockMvc mockMvc; + @Autowired + private WebApplicationContext context; + + @BeforeEach + public void setUp(RestDocumentationContextProvider restDocumentation) { + this.mockMvc = MockMvcBuilders.webAppContextSetup(context) + .apply(documentationConfiguration(restDocumentation)) + .build(); + } + @Test @DisplayName("정상 응답 반환 테스트") public void whenNormalEndpointCalled_thenReturnsSuccessResponse() throws Exception { @@ -26,6 +46,7 @@ public void whenNormalEndpointCalled_thenReturnsSuccessResponse() throws Excepti .andExpect(status().isOk()) .andExpect(jsonPath("$.success").value(true)) .andExpect(jsonPath("$.data").value("Success Response Data")) - .andExpect(jsonPath("$.message").value("정상 응답입니다.")); + .andExpect(jsonPath("$.message").value("Successful response.")) + .andDo(document("common/success-response")); } } diff --git a/src/test/java/com/readup/server/common/integration/controller/TestCommonController.java b/src/test/java/com/readup/server/common/integration/controller/TestCommonController.java index e47902d..c896e3b 100644 --- a/src/test/java/com/readup/server/common/integration/controller/TestCommonController.java +++ b/src/test/java/com/readup/server/common/integration/controller/TestCommonController.java @@ -29,6 +29,6 @@ public void throwRepositoryException() { @GetMapping("/test/success") public ApiResponse getSuccessResponse() { - return ApiResponse.success("Success Response Data", "정상 응답입니다."); + return ApiResponse.success("Success Response Data", "Successful response."); } } diff --git a/src/test/java/com/readup/server/common/integration/exception/exception/GlobalExceptionHandlerTest.java b/src/test/java/com/readup/server/common/integration/exception/exception/GlobalExceptionHandlerTest.java index 53d656f..3bdca7f 100644 --- a/src/test/java/com/readup/server/common/integration/exception/exception/GlobalExceptionHandlerTest.java +++ b/src/test/java/com/readup/server/common/integration/exception/exception/GlobalExceptionHandlerTest.java @@ -1,31 +1,52 @@ package com.readup.server.common.integration.exception.exception; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +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 org.springframework.web.context.WebApplicationContext; import com.readup.server.common.integration.controller.TestCommonController; @WebMvcTest(TestCommonController.class) @AutoConfigureMockMvc(addFilters = false) +@ExtendWith(RestDocumentationExtension.class) +@AutoConfigureRestDocs(outputDir = "build/generated-snippets") public class GlobalExceptionHandlerTest { @Autowired private MockMvc mockMvc; + @Autowired + private WebApplicationContext context; + + @BeforeEach + public void setUp(RestDocumentationContextProvider restDocumentation) { + this.mockMvc = MockMvcBuilders.webAppContextSetup(context) + .apply(documentationConfiguration(restDocumentation)) + .build(); + } + @Test @DisplayName("컨트롤러 예외 발생 시 올바른 에러 응답 반환") public void whenControllerExceptionThrown_thenReturnsProperErrorResponse() throws Exception { mockMvc.perform(get("/test/controller")) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.error").value("INVALID_REQUEST")) - .andExpect(jsonPath("$.message").value("Controller exception occurred")); + .andExpect(jsonPath("$.message").value("Controller exception occurred")) + .andDo(document("common/exception/controller-exception")); } @Test @@ -34,7 +55,8 @@ public void whenServiceExceptionThrown_thenReturnsProperErrorResponse() throws E mockMvc.perform(get("/test/service")) .andExpect(status().isNotFound()) .andExpect(jsonPath("$.error").value("RESOURCE_NOT_FOUND")) - .andExpect(jsonPath("$.message").value("Service exception occurred")); + .andExpect(jsonPath("$.message").value("Service exception occurred")) + .andDo(document("common/exception/service-exception")); } @Test @@ -43,6 +65,7 @@ public void whenRepositoryExceptionThrown_thenReturnsProperErrorResponse() throw mockMvc.perform(get("/test/repository")) .andExpect(status().isInternalServerError()) .andExpect(jsonPath("$.error").value("INTERNAL_SERVER_ERROR")) - .andExpect(jsonPath("$.message").value("Repository exception occurred")); + .andExpect(jsonPath("$.message").value("Repository exception occurred")) + .andDo(document("common/exception/repository-exception")); } }