트러블슈팅 : restDocs

이리·2022년 4월 11일
0

velo9

목록 보기
1/3
Spring Rest Docs + MockMVC 테스트를 진행하다가
문제를 해결한 경험이다.

🚀 PathVariable이 먹지 않았던 문제

	@Test
	void writeGet() throws Exception {

		mockMvc.perform(get("/write")
				.param("id", "1"))
			.andExpect(status().isOk())
			//생략
            ;
	}
get방식에서 JSON(.content( )), 쿼리스트링(.param( ))을 잘 사용하고 있었다.
pathVariable이 포함된 컨트롤러도 테스트 해야하여 구글링을 하여보니
[get("/write/{path}", "value")] 이런식으로 쓰는 걸 확인하여
그대로 적용하니 익셉션이 발생하였다.

java.lang.IllegalArgumentException: urlTemplate not found.
If you are using MockMvc did you use RestDocumentationRequestBuilders
to build the request?

해당 메세지를 그대로 긁어 구글링을 하여보니 경로파라미터를 사용할때는
MockMvcRequestBuilders 아닌 RestDocumentationRequestBuilders의 get()을
사용하여야 한다고 한다.
	@Test
	void series() throws Exception {
		this.mockMvc.perform(RestDocumentationRequestBuilders.get("/{nickname}/series", "admin"))
			.andExpect(status().isOk())
			//생략
            ;
	}

🚀 문서에 굳이 넣고 싶지 않은 이들이 있다면

	@Test
	void series() throws Exception {
		this.mockMvc.perform(RestDocumentationRequestBuilders.get("/{nickname}/series", "admin"))
			.andExpect(status().isOk())
			.andDo(document("GetSeries", pathParameters(
					parameterWithName("nickname").description("")
				),
				responseFields(
					fieldWithPath("data.content").description("").optional(),
					fieldWithPath("data.size").description("").optional(),
					fieldWithPath("data.number").description("").optional(),
					fieldWithPath("data.first").description("").optional(),
					fieldWithPath("data.last").description("").optional(),
					fieldWithPath("data.numberOfElements").description("").optional(),
					fieldWithPath("data.empty").description("").optional(),
					fieldWithPath("subData").description("").optional()
				)
			));
	}
기본적으로 요청과 응답의 필드(또는 파라미터 등)와 문서화할 필드가 일치해야한다.

그렇지 않으면 아래와 같은 익셉션이 발생한다.

org.springframework.restdocs.snippet.SnippetException:
The following parts of the payload were not documented:

하지만 어떤 이유로 추가하고 싶지 않은 경우가 있다.

원래는 이 문제 때문이 아니라
restController라 json으로 resp, req를 받아야 하는데,
Object안에 Object가 있는 경우에 어떻게 표현해야하는지를 찾다가

.을 찍고 들어가는 방법도 찾았고,
relaxed~를 이용하는 방법을 얻어 걸린 듯 찾은 것이다.
	@Test
	void series() throws Exception {
		this.mockMvc.perform(RestDocumentationRequestBuilders.get("/{nickname}/series", "admin"))
			.andExpect(status().isOk())
			.andDo(document("GetSeries", pathParameters(
					parameterWithName("nickname").description("")
				),
				relaxedResponseFields(
					fieldWithPath("data.content").description("").optional(),
					fieldWithPath("data.size").description("").optional(),
					fieldWithPath("data.number").description("").optional(),
					fieldWithPath("data.first").description("").optional(),
					fieldWithPath("data.last").description("").optional(),
					fieldWithPath("data.numberOfElements").description("").optional(),
					fieldWithPath("data.empty").description("").optional(),
					fieldWithPath("subData").description("").optional()
				)
			));
	}
위와 같이 relaxed~가 붙은 메서드를 사용하면 원하는 것만 사용할 수 있다.

물론 relaxed가 붙지 않은 메서드는 요소가 완전히 같아야 하기 때문에,
검증적인 측면에서 장점이 있을 것이라고 생각한다.

🚀 field 아닌 parameter일 때 고생한 것

requestFields(), responseFields() - fieldWithPath 에서
필드란 json {"field":"value"} 에서의 필드를 의미한다.

쿼리스트링, pathVariable을 문서화 및 커스텀 해야할 때는 다음과 같이 하여야 한다.
	pathParameters(
    	parameterWithName("nickname").description("")
	)
    requestParameters(
    	parameterWithName("id").description(").optional()
	)
|===
|경로파라미터|설명

{{#parameters}}

|{{#tableCellContent}}`+{{name}}+`{{/tableCellContent}}
|{{#tableCellContent}}{{description}}{{/tableCellContent}}

{{/parameters}}
|===
{{#fields}} 아닌 {{#parameters}}로,
}`+{{path}}+` 아닌 `+{{name}}+`이다.

이는 바로 위 메서드 이름에서 유추할 수 있는 부분이다.

이 밖에도 restDocs를 공부하면서
Andy Wilkinson라는 분의 도움을 많이 받았다.

해당 관련해서 어딜가나 링크되어있는 저장소의 주인이다.
profile
어제보다 나은 사람이 되자

0개의 댓글