본문 바로가기

개발(합니다)/Java&Spring

[spring boot 설정하기-7] restdocs 설정 및 테스트 소스

반응형

 

swagger와 유사하게 API를 자동으로 문서화할 수 있도록 도와줍니다.

swagger의 장점은 적용하기 쉽고, api 테스트 화면 제공이고

단점으로는 어노테이션을 추가, 동기화가 불일치할 수 있음

restdocs의 장점은 코드에 영향을 받지 않고 테스트가 성공 후 문서화가 되고

단점은 적용이 어려움

아래 사이트에서 관련 정보를 얻을 수 있습니다.

docs.spring.io/spring-restdocs/docs/current/reference/html5/

www.baeldung.com/spring-rest-docs


1. 의존성 추가

plugins {
    id 'org.asciidoctor.convert' version "1.5.6" // (1)
}

dependencies {

    asciidoctor 'org.springframework.restdocs:spring-restdocs-asciidoctor'
    testCompile 'org.springframework.restdocs:spring-restdocs-mockmvc'

}


// restdocs

ext {
    snippetsDir = file('build/generated-snippets')
}

test {
    outputs.dir snippetsDir
}

asciidoctor {
    inputs.dir snippetsDir
    dependsOn test
}


bootJar {
    dependsOn asciidoctor
    from ("${asciidoctor.outputDir}/html5") {
        into 'docs/asciidoc'
    }
}

2. Restdocs 테스트

패키지 구성은 아래와 같습니다.

2-1. RestdocsController.java

package com.otrodevym.spring.base.common.restdocs;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;


@RestController
@RequestMapping("/restdocs")
public class RestdocsController {

    @GetMapping("/hello/{name}")
    public ResponseEntity<RestdocsTest> hello(@PathVariable String name) {
        return ResponseEntity.ok().body(new RestdocsTest(name, "안녕!"));
    }
}

2-2. RestdocsTest.java

package com.otrodevym.spring.base.common.restdocs;

import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;



@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class RestdocsTest {
    private String name;
    private String message;

    @Builder
    public RestdocsTest(String name, String message) {
        this.name = name;
        this.message = message;
    }
}

2-3. Postman 테스트

localhost:9090/restdocs/hello/otrodevym

3. 테스트 및 문서화

3-1. BaseApplicationTests.java

기본적인 테스트 소스를 작성합니다.
.andDo(document("index"));가 테스트 코드를 만드는 소스입니다.

package com.otrodevym.spring.base;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.restdocs.ManualRestDocumentation;
import org.springframework.restdocs.RestDocumentationContextProvider;
import org.springframework.restdocs.RestDocumentationExtension;
import org.springframework.test.context.event.annotation.AfterTestMethod;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MockMvcBuilder;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.testng.annotations.AfterMethod;

import java.lang.reflect.Method;

import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;


@SpringBootTest
@ExtendWith({RestDocumentationExtension.class, SpringExtension.class})
class BaseApplicationTests {

    @Autowired
    private WebApplicationContext webApplicationContext;

    private MockMvc mockMvc;

    @Test
    void contextLoads() {
    }

    @BeforeEach
    public void setUp(RestDocumentationContextProvider restDocumentation) {
        this.mockMvc =
                MockMvcBuilders
                        .webAppContextSetup(this.webApplicationContext)
                        .apply(documentationConfiguration(restDocumentation))
                        .build();
    }

    @AfterMethod
    public void tearDown() {
//        this.restDocumentation.afterTest();
    }


    @Test
    public void restTest() {
        try {
            this.mockMvc.perform(get("/hello/test").accept(MediaType.APPLICATION_JSON))
                    .andExpect(status().isOk())
                    .andDo(document("index"));
        } catch (Exception e) {
            e.printStackTrace();
        }
//        try {
//            this.mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andDo(document("index"));
//        } catch (Exception e) {
//            e.printStackTrace();
//        }

        // given
//        String name = "otrodevym";
//
//        // when
//        try {
//            mockMvc.perform(get("/hello/" + name)
//                    .characterEncoding("utf-8")
//                    .accept(MediaType.APPLICATION_JSON))
//                    .andExpect(status().isOk())  // then
//                    .andExpect(jsonPath("$.name").value(name))
//                    .andDo(document("hello")); // (3)
//        } catch (Exception e) {
//            e.printStackTrace();
//        }

    }
}

3-2. generated-snippets/index/*.adoc과 통합 adoc 파일 설정

3-2-1..adoc으로 끝나는 파일들이 생깁니다.

파일을 열어보면 소스 및 미리보기를 확인할 수 있습니다.

adoc 문서 작성 방법

아래 사이트에서 사용 방법을 확인할 수 있습니다.
https://docs.asciidoctor.org/home/
https://asciidoctor.org/docs/

3-2-2. adoc 통합 관리 파일 생성

adoc 파일들을 통합 관리 할 수 있는 adoc 파일을 생성합니다.

이 부분은 기존에 gradle에서 설정하는 내용과 일치해야 합나다.

아래 소스 코드를 입력하면 원하는 위치에서 adoc 파일들을 가져올 수 있습니다.

ifndef::snippets[]
:snippets: ../../../build/generated-snippets
endif::[]

== User App API

=== API 문서 자동생성

CURL:
include::{snippets}/index/curl-request.adoc[]

파일의 위치를 찾지 못하는 경우 다시 찾아주는 역할을 합니다.

ifndef::snippets[]
:snippets: ../../../build/generated-snippets
endif::[]

원하는 파일을 가져와 문서화를 합니다.
CURL:
include::{snippets}/index/curl-request.adoc[]

CURL:
include::{snippets}/hello/curl-request.adoc[]

Request Parameters:
include::{snippets}/hello/http-request.adoc[]

Request HTTP Example:
include::{snippets}/hello/http-request.adoc[]

=== Response
Response:
include::{snippets}/hello/http-response.adoc[]

3-3. index.html 파일 생성

이제 gradle을 빌드하면 /build/asciidoc/html/index.html 파일이 생성됩니다.

아래와 같이 확인할 수 있습니다.

반응형