[TDD] Spring REST Docs 도입기

이홍준·2023년 9월 5일
0

TDD

목록 보기
3/3
post-thumbnail

테스트 코드를 짜면서 개발하던 중에 기존에 쓰던 Swagger와 다른 Spring REST Docs라는 모듈을 처음 알게 되었다. 솔직히 당장은 혼자 사용하는데 필요한 것인가 싶었지만 이번에는 호기심때문에 도입도 해볼겸 어떤건지 공부도 해보는 시간을 가지게 되었다. Spring Rest Docs가 무엇인지에 대한 것은 공식문서나 기타 블로그들이 더 설명을 더 잘해준다고 생각하기 때문에 간단한 설명 요약 후 바로 코드로 시작하고자 한다.

Spring REST DOCS의 특징

  • 작성한 테스트 코드들의 최신화가 보장 되어있다. → 테스트가 통과해야만 작성되기 때문이다.
  • 문서 형태는 md로 사용할 수 있지만 주로 Asciidoctor 형식을 사용한다.

기본 셋팅 - build.gradle(groovy)

plugins {
    ...
    id 'org.asciidoctor.jvm.convert' version '3.3.2' // 플러그인 등록
}
...

configurations {
    asciidoctorExt // configuration 등록
    compileOnly {
        extendsFrom annotationProcessor
    }
}
...
dependencies {
		...
    asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor'
    testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
}

ext {
    snippetsDir = file('build/generated-snippets') // 빌드될 adoc 경로폴더 정의
}

test {
    outputs.dir snippetsDir
    ...
}

asciidoctor {
    dependsOn test // test 다음 실행 설정
    inputs.dir snippetsDir 
    attributes 'snippets': snippetsDir // 빌드된 snippets 경로(실행된 서버에서)
    doFirst {
        delete 'src/main/resources/static/docs' // 기존 문서파일 삭제
    }
}

*bootJar* {
    dependsOn asciidoctor // asciidoctor 다음 실행 설정
    copy {
        from "build/docs/asciidoc" // 빌드폴더에 있는 adoc파일들을 from->into
        into "src/main/resources/static/docs"
    }
}

실제 코드 작성

간단하게 유저를 생성하는 기능으로 예시를 들었다.


...

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/users")
class UserController {
    private final CreateUserUseCase createUserUseCase;
    @PostMapping
    public SuccessApiResponse createUser(@RequestBody CreateUserRequest createUserRequest){
        CreateUserCommand userCommand = CreateUserCommand.builder()
                .email(createUserRequest.getEmail())
                .name(createUserRequest.getName())
                .nickname(createUserRequest.getNickname())
                .password(createUserRequest.getPassword())
                .build();
        createUserUseCase.createUser(userCommand);
        return SuccessApiResponse.of();
    }
}

테스트 코드 작성

해당 컨트롤러에 대한 통합테스트를 작성해 보았다. PayloadDocumentation에 있는 함수들을 통해서 adoc형식의 스니펫들을 생성할 요소들을 정의한다.

import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
...

@AutoConfigureMockMvc 
@AutoConfigureRestDocs // SpringRestDocs 자동 설정
@SpringBootTest
class UserApiDocumentation {
    @Autowired
    private MockMvc mockMvc;
    @Autowired
    private ObjectMapper objectMapper;

    @Test
    public void createUser() throws Exception {
        CreateUserRequest createUserRequest = new CreateUserRequest("zxc123@naver.com", "zxc", "dd", "dd");
        mockMvc.perform(post("/api/v1/users")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(createUserRequest)))
                .andExpect(status().isOk())
                .andDo(print())
                .andDo(document("create-user", // 스니펫 저장될 폴더 이름
                        PayloadDocumentation.requestFields( // request 필드 목록 등록
                                fieldWithPath("email").description("유저 이메일"), 
                                fieldWithPath("password").description("유저 패스워드"),
                                fieldWithPath("nickname").description("유저 닉네임"),
                                fieldWithPath("name").description("유저 이름")
                        )
                ));
    }
}

테스트 빌드하기

해당 테스트를 실행하면 build.gradle에서 설정했었던 경로인 build/generated-snippets 에 스니펫들이 등록되어있다.

AsciiDoc 플러그인 설치

AsciiDoc파일을 인텔리제이에서 미리보기를 하려면 해당 플러그인을 설치해야만 한다.

이런식으로 볼 수 있게 된다. (인텔리제이 pro 버전만 해당...)

API문서 작성

src/docs/asciidoc 폴더를 생성하고 adoc파일을 생성해준다. (파일명은 아무거나가능)
다른 블로그에서는 *.adoc 로 하는 사람들도 있었는데, 해당 파일명은 Mac에서는 되는데 Windows에는 허용되지 않는 이름이니 유의하고자 한다.

= API 문서
:toc: left
:toclevels: 2
:sectlinks:


== 서론

API 문서에 오신 것을 환영합니다!

== 사용자 API

include::{snippets}/create-user/request-fields.adoc[]

include::{snippets}/create-user/http-request.adoc[]

include::{snippets}/create-user/http-response.adoc[]

asciidoctor 실행

이제 작성한 adoc를 html로 추출하고자한다. build.gradle 파일에 해당 스크립트의 초록색 버튼을 눌러서 실행시킨다.(dependsOn으로 인해 asciidoctor로 정의했던 스크립트도 실행이 같이 됨)

build/docs/asciidoc/index.html 이 등록됨을 확인 해볼 수 있다.

설정한 경로대로 static/docs/index.html -> localhost:8080/docs/index.html 경로로 들어가면 설정한 API 문서를 볼 수 있게 된다.

Build

실제 서버를 빌드시 경로 설정한 대로 src/main/resources/static/docs에 복사 된다.

결론

Spring REST Docs를 쓰면서 실무에서도 API정의서나 테스트관련 문서들을 작성하다 보면 Excel같은 문서들로 봤었는데, 매번 최신화를 해야하는 번거로움이 있었다. 혼자 사용하는 데에는 큰 장점을 못느끼겠지만 커뮤니케이션적인 요소가 많이 필요하게 되는 상황인 구성원들이 다양해질수록 큰 효과를 발휘할 것이라고 느꼈다. 그리고 다른 얘기로는 build.gradle에서 스크립트를 정의하는 groovy언어에 대해서 좀 더 익숙하게 사용하게 되는 계기가 되었던 것 같다. 나중에 Spring 관련 큰 프로젝트를 할 때에 TDD를 사용한다면 꼭 도입하자고 말하는 데 근거가 될 자료가 되기에 도움이 될 것이라고 생각한다.


References

profile
I'm a web developer.

0개의 댓글