diff --git a/build.gradle b/build.gradle index 938db503..eab2f472 100644 --- a/build.gradle +++ b/build.gradle @@ -68,7 +68,7 @@ dependencies { implementation 'org.testcontainers:testcontainers:1.19.3' // Rest Assured - testImplementation 'io.rest-assured:rest-assured:5.3.2' + testImplementation 'org.springframework.restdocs:spring-restdocs-restassured' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test' diff --git a/src/docs/asciidoc/index.adoc b/src/docs/asciidoc/index.adoc index 12f432cc..bc7c822e 100644 --- a/src/docs/asciidoc/index.adoc +++ b/src/docs/asciidoc/index.adoc @@ -66,4 +66,8 @@ Golden-Ticket API adheres as closely as possible to standard HTTP and REST conve | 500 Internal Server Error | An unexpected internal server error occurred -|=== \ No newline at end of file +|=== + += 사용자 기능 + +include::user.adoc[] diff --git a/src/docs/asciidoc/user.adoc b/src/docs/asciidoc/user.adoc new file mode 100644 index 00000000..851ee3d1 --- /dev/null +++ b/src/docs/asciidoc/user.adoc @@ -0,0 +1,15 @@ +== 회원가입 + +=== HTTP request fields +include::{snippets}/user/join/success/request-fields.adoc[] + +=== HTTP request +include::{snippets}/user/join/success/http-request.adoc[] + +=== HTTP response fields + +include::{snippets}/user/join/success/response-fields.adoc[] + +=== HTTP request + +include::{snippets}/user/join/success/http-response.adoc[] diff --git a/src/test/java/site/goldenticket/common/config/ApiDocumentation.java b/src/test/java/site/goldenticket/common/config/ApiDocumentation.java index 49a0ccd2..9210da15 100644 --- a/src/test/java/site/goldenticket/common/config/ApiDocumentation.java +++ b/src/test/java/site/goldenticket/common/config/ApiDocumentation.java @@ -1,33 +1,35 @@ package site.goldenticket.common.config; import com.fasterxml.jackson.databind.ObjectMapper; +import io.restassured.builder.RequestSpecBuilder; +import io.restassured.specification.RequestSpecification; +import org.junit.jupiter.api.BeforeEach; 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.context.SpringBootTest; +import org.springframework.restdocs.RestDocumentationContextProvider; import org.springframework.restdocs.RestDocumentationExtension; import org.springframework.restdocs.operation.preprocess.OperationRequestPreprocessor; import org.springframework.restdocs.operation.preprocess.OperationResponsePreprocessor; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.restdocs.snippet.Attributes.Attribute; import static org.springframework.restdocs.operation.preprocess.Preprocessors.*; -import static org.springframework.restdocs.snippet.Attributes.key; +import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration; -@SpringBootTest -@AutoConfigureMockMvc -@AutoConfigureRestDocs @ExtendWith(RestDocumentationExtension.class) -public abstract class ApiDocumentation { +public abstract class ApiDocumentation extends ApiTest { private static final String BASE_URL = "localhost"; @Autowired protected ObjectMapper objectMapper; - @Autowired - protected MockMvc mockMvc; + protected RequestSpecification spec; + + @BeforeEach + public void setUpDocs(RestDocumentationContextProvider restDocumentation) { + this.spec = new RequestSpecBuilder() + .addFilter(documentationConfiguration(restDocumentation)) + .build(); + } protected OperationRequestPreprocessor getDocumentRequest() { return preprocessRequest(modifyUris().host(BASE_URL).removePort(), prettyPrint()); @@ -36,20 +38,4 @@ protected OperationRequestPreprocessor getDocumentRequest() { protected OperationResponsePreprocessor getDocumentResponse() { return preprocessResponse(prettyPrint()); } - - protected Attribute getTimeFormat() { - return key("format").value("hh:mm"); - } - - protected Attribute getDateFormat() { - return key("format").value("yyyy-MM-dd"); - } - - protected Attribute getPhoneFormat() { - return key("format").value("000-0000-0000"); - } - - protected Attribute getEmailFormat() { - return key("format").value("email@gmail.com"); - } } diff --git a/src/test/java/site/goldenticket/common/config/ApiTest.java b/src/test/java/site/goldenticket/common/config/ApiTest.java index 67eb830c..2a4fac10 100644 --- a/src/test/java/site/goldenticket/common/config/ApiTest.java +++ b/src/test/java/site/goldenticket/common/config/ApiTest.java @@ -29,7 +29,7 @@ public abstract class ApiTest { private TokenProvider tokenProvider; @LocalServerPort - private int port; + protected int port; public User user; public String accessToken; diff --git a/src/test/java/site/goldenticket/domain/user/controller/UserControllerTest.java b/src/test/java/site/goldenticket/domain/user/controller/UserControllerTest.java index 0540f4ce..82b2c5e3 100644 --- a/src/test/java/site/goldenticket/domain/user/controller/UserControllerTest.java +++ b/src/test/java/site/goldenticket/domain/user/controller/UserControllerTest.java @@ -1,5 +1,6 @@ package site.goldenticket.domain.user.controller; +import io.restassured.RestAssured; import io.restassured.path.json.JsonPath; import io.restassured.response.ExtractableResponse; import io.restassured.response.Response; @@ -7,7 +8,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.crypto.password.PasswordEncoder; -import site.goldenticket.common.config.ApiTest; +import site.goldenticket.common.config.ApiDocumentation; import site.goldenticket.domain.user.dto.*; import site.goldenticket.domain.user.entity.User; import site.goldenticket.domain.user.repository.UserRepository; @@ -16,11 +17,15 @@ import static org.junit.jupiter.api.Assertions.assertAll; import static org.springframework.http.HttpStatus.CREATED; import static org.springframework.http.HttpStatus.OK; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.springframework.restdocs.payload.JsonFieldType.*; +import static org.springframework.restdocs.payload.PayloadDocumentation.*; +import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document; import static site.goldenticket.common.utils.RestAssuredUtils.*; import static site.goldenticket.common.utils.UserUtils.*; @DisplayName("UserController 검증") -class UserControllerTest extends ApiTest { +class UserControllerTest extends ApiDocumentation { @Autowired private UserRepository userRepository; @@ -36,7 +41,41 @@ void join() { String url = "/users"; // when - ExtractableResponse result = restAssuredPost(url, request); + ExtractableResponse result = RestAssured + .given(spec).log().all() + .contentType(APPLICATION_JSON_VALUE) + .body(request) + .filter(document( + "user/join/success", + getDocumentRequest(), + getDocumentResponse(), + requestFields( + fieldWithPath("name").type(STRING) + .description("이름"), + fieldWithPath("nickname").type(STRING) + .description("닉네임"), + fieldWithPath("email").type(STRING) + .description("이메일"), + fieldWithPath("password").type(STRING) + .description("비밀번호"), + fieldWithPath("phoneNumber").type(STRING) + .description("휴대폰번호"), + fieldWithPath("yanoljaId").type(NUMBER) + .description("야놀자 회원 식별값").optional(), + fieldWithPath("agreement.isMarketing").type(BOOLEAN) + .description("마케팅 동의 여부") + ), + responseFields( + fieldWithPath("status").ignored(), + fieldWithPath("message").ignored(), + fieldWithPath("data").type(NUMBER) + .description("사용자 식별값") + ) + )) + .when() + .post(url) + .then().log().all() + .extract(); // then assertThat(result.statusCode()).isEqualTo(CREATED.value());