Spring MVC/04.Rest

[spring boot]MockMVC 테스트시 response content의 한글 깨짐

  • -

간만에 SpringBoot 기반의 Rest 애플리케이션을 테스트 하다 보니 한글 문제가 발생해서 대처 방안을 정리한다.

 

 MockMVC 테스트 시 response content의 한글 깨짐 문제

 

MockMVC를 이용한 Rest 서비스의 단위 테스트

일반적으로 Service 등을 Mocking 하지 않고 그대로 사용하기 위해서는 아래와 같이 단위 테스트 할 수 있다.

@SpringBootTest
public class CatoryControllerTest {

	@Autowired
	CategoryController cController;
	
	MockMvc mock;
	
	@BeforeEach
	public void setup() {
		mock = MockMvcBuilders.standaloneSetup(cController).build();
	}
	
	@Test
	public void findByNameTest() throws Exception {
		mock.perform(get("/api/category").param("engName", "Backtracking"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.content[0].korName", equalTo("양방향 탐색")))
            .andExpect(jsonPath("$.content.length()", is(7)));
	}
}

 

갑자기 내용 전체를 출력해보고 싶었다.

단위테스트는 통과 했지만 불현듯 전체 반환 내용을 출력해보고 싶었다. 따라서 단위 테스트를 다음과 같이 변경해보있다.

@Test
public void findByNameTest() throws Exception {
    MvcResult result =mock.perform(get("/api/category").param("engName", "search"))
        .andExpect(status().isOk())
        .andExpect(jsonPath("$.content[0].korName", equalTo("양방향 탐색")))
        .andExpect(jsonPath("$.content.length()", is(7)))
        .andReturn();
		
    String content = result.getResponse().getContentAsString();
    System.out.println(content);
}

그리고 출력된 결과를 확인해봤더니 매우 신기한 결과가 나왔다.

{"content":[{"id":4451,"korName":"양방향 탐색","engName":"Bidirectional Search","pcats":null},
            {"id":4308,"korName":"이분 탐색","engName":"Binary Search","pcats":null},
            {"id":4309,"korName":"너비 우선 탐색","engName":"Breadth-first Search","pcats":null},
            {"id":4313,"korName":"깊이 우선 탐색","engName":"Depth-first Search","pcats":null},
            {"id":4397,"korName":"병렬 이분 탐색","engName":"Parallel Binary Search","pcats":null},
            {"id":4366,"korName":"매개 변수 탐색","engName":"Parametric Search","pcats":null},
            {"id":4383,"korName":"삼분 탐색","engName":"Ternary Search","pcats":null}]
,"pageable":{. . .}
}

위에서 보듯 content에 있는 korName이 깨져있는 것이다. 

신기한 점은 jsonPath에서 비교했을 때는 어떻게 equalTo에서 true가 나왔을까이다. "양방향 탐색"과 "양방향 탐색"가 어떻게 같을까?

 

대책

정확한 문서는 찾지 못했지만 stackoverflow.com을 살펴보다보니 jsonPath는 언제나 utf-8로 변환해서 읽는다고 한다. 즉 아래처럼 사용한다는 이야기이다.

@Test
public void findByNameTest() throws Exception {
	MvcResult result =mock.perform(get("/api/category").param("engName", "search"))
        .andExpect(status().isOk())
        .andExpect(jsonPath("$.content[0].korName", equalTo("양방향 탐색")))
        .andExpect(jsonPath("$.content.length()", is(7)))
        .andReturn();
	
	String content = result.getResponse().getContentAsString(Charset.forName("UTF-8"));
	System.out.println(content);
}

UTF-8로 변환해버렸으니 당연히 결과는 제대로 출력된다.

{"content":[{"id":4451,"korName":"양방향 탐색","engName":"Bidirectional Search","pcats":null},
            {"id":4308,"korName":"이분 탐색","engName":"Binary Search","pcats":null},
            {"id":4309,"korName":"너비 우선 탐색","engName":"Breadth-first Search","pcats":null},
            {"id":4313,"korName":"깊이 우선 탐색","engName":"Depth-first Search","pcats":null},
            {"id":4397,"korName":"병렬 이분 탐색","engName":"Parallel Binary Search","pcats":null},
            {"id":4366,"korName":"매개 변수 탐색","engName":"Parametric Search","pcats":null},
            {"id":4383,"korName":"삼분 탐색","engName":"Ternary Search","pcats":null}],
  "pageable":{...}
}

하지만 위의 코드는 응답을 가져온 후 다시 변환한 녀석이라 웬지 꺼림직하다.

보다 근본적인 방법은 MockMvc를 생성하면서 CharacterEncodingFilter를 삽입해주는 것이다.

@BeforeEach
public void setup() {
	mock = MockMvcBuilders.standaloneSetup(cController)
		              .addFilter(new CharacterEncodingFilter("UTF-8", true))
		              .build();
}
	
@Test
public void findByNameTest() throws Exception {
	MvcResult result =mock.perform(get("/api/category").param("engName", "search"))
        .andExpect(status().isOk())
        .andExpect(jsonPath("$.content[0].korName", equalTo("양방향 탐색")))
        .andExpect(jsonPath("$.content.length()", is(7)))
        .andReturn();
	// 결과를 별도로 encoding 처리하지 않는다.
	String content = result.getResponse().getContentAsString();
	System.out.println(content);
}

 

아마도

위와 같이 CharacterEncodingFilter를 적용해서 encoding 문제를 해결했지만 talend 같은 rest api tester 들을 이용해보면 별다른 조작 없이 한글 데이터가 잘 넘어온다.

 

이 문제를 곰곰히 생각해다 controller에서 response 객체를 확인해보니 일반적인 호출에서와 MockMvc를 통한 호출에서 HttpServletResponse 객체가 다르다는 것을 알게 되었다.

  • 일반 호출: org.apache.catalina.connector.ResponseFacade
  • MockMvc를 통한 호출: org.springframework.mock.web.MockHttpServletResponse

더이상 코드를 까보지는 않았지만 ResponseFacade는 utf-8로 처리하고 MockHttpServletResponse는 그렇지 않기 때문에 filter와 같은 보조 수단을 이용해서 encoding을 처리해줘야 하는것으로정리 하고자 한다. ㅜㅜ

 

'Spring MVC > 04.Rest' 카테고리의 다른 글

[swagger]swagger와 interceptor  (0) 2021.12.09
[springboot]CORS 설정  (0) 2021.09.08
03. RestTemplate  (0) 2020.07.14
02. REST를 위한 단위 테스트  (0) 2020.07.13
01.Rest  (0) 2020.07.10
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.