인프런 커뮤니티 질문&답변

OMG님의 프로필 이미지

작성한 질문수

스프링 기반 REST API 개발

스프링 REST Docs 각종 문서 조각 생성하기

질문있습니다.

해결된 질문

21.03.19 19:24 작성

·

623

4

좋은 강의 만들어주셔서 많이 배우고 있습니다. 감사합니다.

다름이 아니라 강의 수강 중 테스트가 실패하여 문의드립니다.

해당 강의 전까지는 메이븐 프로젝트로 생성하여 의존성 추가해서 강의의 스프링부트 버전(2.1.0.RELEASE)로 진행하여 문제 없이 진행하였는데 
EventControllerTests - createEvent 테스트코드 작성시

mockMvc.perform(post("/api/events/")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(event)))
.andDo(print())
.andExpect(status().isCreated())
.andExpect(jsonPath("id").exists())
.andExpect(jsonPath("$.id").exists())
.andExpect(header().exists(HttpHeaders.LOCATION))
.andExpect(header().string(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("free").value(false))
.andExpect(jsonPath("offline").value(true))
.andExpect(jsonPath("eventStatus").value(EventStatus.DRAFT.name()))
.andExpect(jsonPath("_links.self").exists())
//.andExpect(jsonPath("$._links.self").exists())
.andExpect(jsonPath("_links.query-events").exists())
.andExpect(jsonPath("_links.update-event").exists())
.andDo(document("create-event",
links(
linkWithRel("self").description("link to self"),
linkWithRel("query-events").description("link to query events"),
linkWithRel("update-event").description("link to update an existing event")
)
))
;

위와 같이 작성하면 실패하고

org.springframework.restdocs.snippet.SnippetException: Links with the following relations were not found in the response: [self, update-event, query-events]

.andDo(document("create-event",
links(halLinks(),
linkWithRel("self").description("link to self"),
linkWithRel("query-events").description("link to query events"),
linkWithRel("update-event").description("link to update an existing event")
)
))
;

links의 첫번째 인자로 haLinks()를 주면 테스트가 성공하는 것을 확인하였습니다. 
원인을 파악하기 위해 검색도 해보고 강의도 다시 보던 중에 KSUG에서 발표하셨다고 하던 이전 자료(해당 강의의 시작)를 보니 halLinks()가 있는 것을 보았고 해당 코드가 있는 깃랩(https://gitlab.com/whiteship/natural/-/blob/master/src/test/java/me/whiteship/natural/event/EventControllerTests.java)에서도 보니 halLinks()가 있는 것을 확인하였습니다.  메이븐 프로젝트로 생성해서 버전이랑 의존성 꼬이는 문제는 없을것 같은데

<artifactId>asciidoctor-maven-plugin</artifactId>
<version>1.5.8</version>

asciidoctor-maven-plugin의 버전이 제가 작성한 버전은 1.5.8이고 기선님이 사용한 버전은 1.5.3인 차이만 확인하였습니다.

무슨 차이로 인해 테스트가 실패하는 것인지 감이 안잡히는데 기선님은 두 가지 방식 다 진행하였고 성공하여서 질문드립니다.

테스트 실패 시 출력하는 요청,응답 헤더

MockHttpServletRequest:

 Headers = {Content-Type=[application/json;charset=UTF-8], Accept=[application/json]}

MockHttpServletResponse:

Headers = {Location=[http://localhost:8080/api/events/1], Content-Type[application/json;charset=UTF-8]}

json 출력결과도 첨부합니다.

{

  • "id" : 1,
  • "name" : Spring,
  • "description" : REST API Development with Spring,
  • "beginEnrollmentDateTime" : 2018-11-23T14:21:00,
  • "closeEnrollmentDateTime" : 2018-11-24T14:21:00,
  • "beginEventDateTime" : 2018-11-25T14:21:00,
  • "endEventDateTime" : 2018-11-26T14:21:00,
  • "location" : 강남역 D2 스타텁 팩토리,
  • "basePrice" : 100,
  • "maxPrice" : 200,
  • "limitOfEnrollment" : 100,
  • "offline" : true,
  • "free" : false,
  • "eventStatus" : DRAFT,
  • "_links" : -{
    • "self" : -{
      • "href" : http://localhost:8080/api/events/1
      },
    • "query-events" : -{
      • "href" : http://localhost:8080/api/events
      },
    • "update-event" : -{
      • "href" : http://localhost:8080/api/events/1
      }
    }

}

깃헙 링크도 첨부합니다!
https://github.com/rshak8912/rest

답변 3

0

OMG님의 프로필 이미지
OMG
질문자

2021. 03. 20. 08:55

제가 HAL 방식을 사용하지 않은 것은

IDE 내에서 HAL 을 불러오지 못하여서 인데 설명이 미흡했었나봅니다. 보통 이럴 경우 먼저 의존성 버전을 바꿔보거나 프로젝트 새로 만들어 보는데 놓쳤습니다..

제가 그럴것이다 라고 가정하고 넘어가기 일쑤였는데 확답을 해주시니 마음의 안정이 오네요..ㅋㅋ
답변 감사합니다 !!

============

알려주신 키워드로 테스트 해봤는데
MediaType이 아니라 MediaTypes로 하니까 되네요...ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ
저의 무지함에 다시 한번 반성하며 기선님의 친절함과 강의에 감사함을 느낍니다..ㅠㅠ

0

백기선님의 프로필 이미지
백기선
지식공유자

2021. 03. 20. 00:56

네 Content Type하고 관련이 있습니다. produces에 MediaTypes.HAL_JSON_VALUE을 쓰지 않은 경우에는  halLinks()를 추가해서 문서를 생성해야 hal 링크를 추출할 수 있습니다.

HAL_JSON 등은 스프링 MVC가 제공하는 MediaType이 아니라 스프링 HATEOAS가 제공하는 MediaTypes에 들어있습니다.

컨트롤러에서 MediaTypes.HAL_JSON_VALUE를 사용하시고, 테스트 코드에서 contentType, accept, andExpect에서 기대하는 헤더값을 적절히 변경핫시면 halLinks() 없이도 테스트가 동작하게 고칠 수 있습니다.

@RequestMapping(value="/api/events", produces = MediaTypes.HAL_JSON_VALUE)

.contentType(MediaTypes.HAL_JSON)
.accept(
MediaTypes.HAL_JSON)
.andExpect(header().string(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE))

.andDo(document("create-event",
links(
linkWithRel("self").description("link to self"),
linkWithRel("query-events").description("link to query events"),
linkWithRel("update-event").description("link to update an existing event")
)

0

OMG님의 프로필 이미지
OMG
질문자

2021. 03. 19. 19:43

추가 질문입니다.

질문하다 생각난 것인데, 제가 강의 실습 시 MediaType.HAL_JSON이 불러와지지 않아서 EventController의 RequestMapping의 produces를 APPLICATION_JSON_VALUE로 진행하였습니다. 이 점 때문에 발생한 문제일까요? 

(질문 후 계속 찾아보다 https://docs.spring.io/spring-restdocs/docs/current/reference/html5/#documenting-your-api-hypermedia-link-formats

여기에서 두 가지 링크 포맷(atom, hal)에 대해서 알게 되었습니다. 강의와 KSUG에서 사용한 스프링부트 버전은 2.1.0으로 동일한데 다른 방식의 링크 포맷을 이용하신 이유가 있을까요?)

HAL_JSON은 비표준이라고 설명하셔서 해당 코드 작성시에 APPLICATION_JSON으로 작성한 것인데

같은 스프링부트 버전이면 관리하는 다른 의존성 버전은 같기에 MediaType의 값들도 같아야 될것같은데  HAL_JSON을 불러오지 못하는 이유가 있을까요?

수강 중에 그러려니하고 넘어갔는데 추가적인 문제가 발생하여 질문이 많아진 점 죄송합니다

OMG님의 프로필 이미지

작성한 질문수

질문하기