#1. 프로젝트 생성 및 의존성 추가
프로젝트를 처음으로 생성하는 경우에는 Spring Initializr 에서 Spring Rest Docs 와 관련된 의존성을 추가합니다.
아래와 같이 최소한 Spring Web과 Spring REST Docs 는 추가해야 합니다.
기존의 프로젝트에 Spring REST Docs를 추가하는 경우에도 Spring initializr 를 사용해서 Dependencies를 추가한 다음,
자동으로 생성된 의존성을 복사해 오는 방법이 괜찮아 보입니다.
initializr가 자동으로 생성해 준 build.gradle 파일은 아래와 같습니다.
plugins {
id 'org.springframework.boot' version '2.5.0'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'org.asciidoctor.convert' version '1.5.8'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
repositories {
mavenCentral()
}
ext {
set('snippetsDir', file("build/generated-snippets"))
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
}
test {
outputs.dir snippetsDir
useJUnitPlatform()
}
asciidoctor {
inputs.dir snippetsDir
dependsOn test
}
뒷 부분에 다시 얘기하겠지만.. 참고로 제 경우에는 이 설정으로 doc의 코드조각인 snippets 까지는 생성됐지만
자동으로 html문서까지 만들어주진 않았기 때문에, 추가적으로 설정한 부분이 있습니다.
#2. 테스트 코드 작성
테스트 코드는 Junit4를 사용해서 작성했기 때문에 gradle 설정을 조금 바꿔주겠습니다.
Junit vintage 엔진을 추가해줍시다.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
// JUnit4
testImplementation('org.junit.vintage:junit-vintage-engine') {
exclude group: 'org.hancrest', module: 'hamcrest-core'
}
}
테스트 코드는 아래와 같이 작성했습니다.
package com.example.demo.controller;
import com.example.demo.entity.TodoMngAct;
import com.example.demo.entity.TodoMngActId;
import com.google.gson.GsonBuilder;
import org.junit.Test;
import org.junit.runner.RunWith;
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.context.annotation.Description;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.*;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.*;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
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;
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureRestDocs(uriHost = "apihost", uriPort = 8090)
public class ItrmControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
@Description("ITRM 저장")
public void saveTodoMngAct() throws Exception {
Map<String, String> param = new HashMap<>();
param.put("TODO_DT", "20210526");
param.put("TODO_ID", "HTW_BSP_A0002.1");
param.put("DESCRIPTION", "테스트");
param.put("PROGRESS", "S");
TodoMngAct todoMngAct = new TodoMngAct(param);
todoMngAct.setUPDATE_DT(LocalDateTime.now());
String jsonString = new GsonBuilder().setPrettyPrinting().create().toJson(param);
mockMvc.perform(
post("/api/saveTodoMngAct")
.contentType(MediaType.APPLICATION_JSON)
.content(jsonString)
.accept(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isOk())
.andDo(document("itrm/{method-name}",
preprocessRequest(prettyPrint()),
preprocessResponse(prettyPrint()),
requestFields(
fieldWithPath("TODO_ID").description("TODO ID"),
fieldWithPath("TODO_DT").description("ITRM수행 일자"),
fieldWithPath("DESCRIPTION").description("점검 결과 기록"),
fieldWithPath("PROGRESS").description("성공이면 S, 실패면 NULL")
))
);
}
}
MockMvc를 사용하는 테스트케이스에서 기본적으로
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
여기까지는 기본적인 작성 방법이고,
@AutoConfigureRestDocs(uriHost = "apihost", uriPort = 8090)
위 어노테이션을 추가하게 되면 RestDocs에 대한 기초 세팅들을 알아서 해줍니다. 커스터마이징이 더 필요하다면 이 설정 대신 커스텀 설정을 사용해도 됩니다.
uriHost 와 uriPort 값은 부가적인 내용으로, 이를 따로 기술하지 않으면 기본값인 localhost:8080 으로 Doc이 작성되어 집니다.
MockMvc를 사용하여, api를 호출하고, 간단히 결과는 status = 200 인지만 체크하는 테스트케이스이며
document("itrm/{method-name}",
// gradle 파일에 정의했던 build/generated-snippets 경로의 /itrm/{메소드이름}/ 폴더에 snippets 파일이 생성됩니다.
// 위 메소드 기준으로는 /itrm/save-todo-mng-act/ 로 생성됩니다.
preprocessRequest(prettyPrint()),
preprocessResponse(prettyPrint()),
// prettyPrint 옵션으로 json requets/response 를 보기 편하게 만들어 줍니다.
requestFields(
fieldWithPath("TODO_ID").description("TODO ID"),
fieldWithPath("TODO_DT").description("ITRM수행 일자"),
fieldWithPath("DESCRIPTION").description("점검 결과 기록"),
fieldWithPath("PROGRESS").description("성공이면 S, 실패면 NULL")
))
// request 필드에 대한 설명을 작성합니다.
#3. 테스트 수행/Snippets 생성
작성된 테스트케이스를 수행하고, 성공적으로 테스트가 완료되었다면,
아래와 같이 snippets 파일이 생성됩니다.
curl-request.adoc / http-request.adoc / http-response.adoc 등등의 조각파일이 생성되고,
http-request.adoc 파일을 하나 열어보면
위 처럼 http Request정보에 대한 조각 문서 내용을 가지고 있습니다.
이제 이 조각 파일들을 이용해서 하나의 문서를 만들어봅시다.
gradle 프로젝트 기준으로(Maven프로젝트는 설정이 다릅니다.) src/docs/asciidoc/index.adoc 문서를 생성합니다.
이 adoc 파일을 추후 static html 파일로 변환되어 url호출시 보여줄 최종 문서가 됩니다.
= ITRM API Document
:doctype: book
:icons: font
:source-highlighter: highlightjs
:toc: left
:toclevels: 3
:sectlinks:
[[introduction]]
== 소개
ITRM 자동화 처리를 위한 API
[[common]]
== 공통 사항
API PORT는 8090
[[save-todo-mng-act]]
== SAVE
=== Request
CURL:
include::{snippets}/itrm/save-todo-mng-act/curl-request.adoc[]
Request Parameters:
include::{snippets}/itrm/save-todo-mng-act/request-body.adoc[]
include::{snippets}/itrm/save-todo-mng-act/request-fields.adoc[]
Request HTTP Example:
include::{snippets}/itrm/save-todo-mng-act/http-request.adoc[]
=== Response
Response:
include::{snippets}/itrm/save-todo-mng-act/http-response.adoc[]
adoc 파일은 Mustache 문법으로 작성되며, 간단히 살펴 보면
테스트 결과로 생성된 조각파일들을 include::{snippets}/itrm/save-todo-mng-act/curl-request.adoc[] 와 같은 식으로 문서내에 include 시켜서 사용한다는 것을 알 수 있습니다.
#4. REST Doc문서 생성
이제 REST Doc 문서를 생성하기 위한 조각파일과, html 문서 생성을 위한 구조작성까지 마쳤으니, 실제 문서를 생성해봅시다.
gradle task > asciidoctor를 실행하면, build/asciidoc/html5/index.html 파일이 생성됩니다.
이 파일이 실제 REST Doc이 되는 html문서이고, 이제 우리는 이를 static resource에 포함해서 배포하기만 하면 됩니다.
다시 build.gradle 파일을 열고 추가적으로 내용을 작성해 줍니다.
task copyDocument(type: Copy) {
dependsOn asciidoctor
from file("build/asciidoc/html5/")
into file("src/main/resources/static/docs")
}
build {
dependsOn copyDocument
}
build task 실행 시, build/asciidoc/html5/ 폴더 하위의 파일들을 src/main/resources/static/docs 로 옮겨주는 작업을 추가하고 gradle build를 수행하면, 정적 html 파일이 resources/static/docs 하위에 복사 되면서 url을 통해 바로 호출할 수 있게 됩니다.
#5. 작성된 문서 확인
생성된 최종 빌드파일을 java -jar 를 통해 수행한 후, http://host:port/docs/index.html 을 호출하면 생성했던 REST Docs를 확인 할 수 있습니다.
java -jar demo-0.0.1-SNAPSHOT.jar
'Spring Boot' 카테고리의 다른 글
javax.inject.Provider 를 사용할 때 UnsatisfiedDependencyException 발생 (0) | 2023.03.12 |
---|---|
[Spring Boot] REST API 제작기 - 2.DB연결(Mybatis) (0) | 2022.03.28 |
[Spring Boot] REST API 제작기 - 1.프로젝트 생성 (0) | 2022.02.17 |
댓글