Skip to content

Commit c071949

Browse files
authored
Update README.md
1 parent d6f661a commit c071949

File tree

1 file changed

+103
-0
lines changed

1 file changed

+103
-0
lines changed

README.md

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,106 @@
22
![Spring Rest Docs Logo](https://user-images.githubusercontent.com/48639421/127739359-3c4982f1-378e-4df0-b690-c4a0083ed3ad.png)
33

44
## Spring Rest Docs가 뭐야
5+
`Spring Rest Docs``Swagger`와 마찬가지로 `Open API`를 생성할 수 있는 라이브러리입니다.
6+
7+
`Swagger``Controller`단에 어노테이션을 붙여 `API`에 대한 설명을 덧붙일 수 있지만
8+
`Spring Rest Docs`는 테스트 코드를 작성함으로써 `Open API`를 구체화할 수 있습니다.
9+
10+
또한 `Swagger`는 어노테이션 기반이기 때문에 구체화한 정보에 대한 검증이 이루어지지 않고
11+
그에 따라 `API`가 변하면서 바뀌어야하는 조건에 대한 정확성과 무결성이 깨지게 됩니다.
12+
하지만 `Spring Rest Docs`는 테스트 코드에서 실제 `Request`가 오지 않았거나, `Response`에 대한 결과가 맞지 않거나,
13+
타입이 맞지 않는 등의 `실제와 다른 정보`를 검증이 가능합니다.
14+
따라서 `Open API`와 실제 `API`의 동작 방식간의 일관성을 유지할 수 있습니다.
15+
16+
## Spring Rest Docs 사용해보기
17+
```kotlin
18+
19+
@Test
20+
fun `모든 학생 조회하기 - OK`() {
21+
val returnValue = listOf(
22+
StudentSearchDto(
23+
studentId = 1,
24+
studentName = "jinhyeok lee",
25+
studentGradeClassNumber = "3417",
26+
),
27+
StudentSearchDto(
28+
studentId = 2,
29+
studentName = "jinhyuk lee",
30+
studentGradeClassNumber = "3517",
31+
),
32+
)
33+
34+
given(studentSearchService.searchAll())
35+
.willReturn(returnValue)
36+
37+
val result = mockMvc.perform(
38+
createRequest<Nothing>(
39+
httpMethod = HttpMethod.GET,
40+
url = "/students",
41+
))
42+
.andExpect(status().isOk)
43+
.andDo(
44+
document(
45+
"모든 학생 조회하기 - OK",
46+
getDocumentRequest(),
47+
getDocumentResponse(),
48+
responseFields(
49+
fieldWithPath("response.students")
50+
.type(JsonFieldType.ARRAY)
51+
.description("조회한 학생들"),
52+
fieldWithPath("response.students[].id")
53+
.type(JsonFieldType.NUMBER)
54+
.description("학생 아이디"),
55+
fieldWithPath("response.students[].name")
56+
.type(JsonFieldType.STRING)
57+
.description("학생 이름"),
58+
fieldWithPath("response.students[].gradeClassNumber")
59+
.type(JsonFieldType.STRING)
60+
.description("학생 학년-반-번호"),
61+
fieldWithPath("errorCode")
62+
.type(JsonFieldType.NULL)
63+
.description("에러 코드"),
64+
fieldWithPath("errorMessage")
65+
.type(JsonFieldType.NULL)
66+
.description("에러 메시지"),
67+
),
68+
),
69+
)
70+
.andReturn()
71+
.response
72+
.contentAsString
73+
.toObject<CommonResponse<StudentAllSearchResponse>>()
74+
75+
verify(studentSearchService).searchAll()
76+
77+
assertThat(result.errorCode).isNull()
78+
assertThat(result.errorMessage).isNull()
79+
assertThat(result.response).isNotNull
80+
assertThat(result.response!!.students)
81+
.map<Long> { it.id }
82+
.contains(1, 2)
83+
assertThat(result.response!!.students)
84+
.map<String> { it.name }
85+
.contains("jinhyeok lee", "jinhyuk lee")
86+
assertThat(result.response!!.students)
87+
.map<String> { it.gradeClassNumber }
88+
.contains("3417", "3517")
89+
}
90+
```
91+
테스트 프레임워크는 `BDD-Mockito`를 이용하였습니다.
92+
겉보기에는 컨트롤러를 테스트하는 코드로 보이지만 눈에 띄는 코드가 있습니다.
93+
`andDo` 메소드를 통해 `document`를 생성하는 코드입니다.
94+
여기서는 위에서 말했던 것처럼 `Request``Response`를 검증하는 역할을 합니다.
95+
96+
첫 번째 인자로는 `API`의 이름을 등록하고,
97+
두, 세 번째 인자로는 `Request``Response`에 대한 설정을 등록하는데
98+
여기서는 나중에 테스트 코드를 빌드하여 생성되는 `asciidoc`에서
99+
`Request``Response`를 예쁘게 찍기 위한 설정을 해두었습니다.
100+
101+
제일 중요한 건 마지막 인자입니다.
102+
여기서 `Response`를 검증하기 위해서는 `responseFields()` 메소드를,
103+
`Request`를 검증하기 위해서는 `requestFields()` 메소드를 사용합니다.
104+
다른 내용은 한 눈에 봐도 무슨 뜻인지 유추하기 쉽습니다.
105+
106+
이렇게 도큐먼트를 생성한 뒤에는 원래 테스트 하던 것처럼
107+
`verify` 해주고, 응답 `assertion` 하시면 됩니다.

0 commit comments

Comments
 (0)