Hello, Freakin world!

[Spring] 컨트롤러 메서드 파리미터 JSON 바인딩 여부 테스트 본문

Spring boot

[Spring] 컨트롤러 메서드 파리미터 JSON 바인딩 여부 테스트

johnna_endure 2020. 8. 10. 12:29

다음의 컨트롤러 계층의 메서드가 있다고 가정합니다.

@ToString
@NoArgsConstructor
@Getter
public class ItemCreateDto {

	@NotNull
	private String name;
	@NotNull
	private Integer price;
	@NotNull
	private Integer stockQuantity;

	private List<ItemDetailDto> details;
}
	@PostMapping("/items")
	public String create(@RequestBody ItemCreateDto createDto) {
		System.out.println(createDto);
		return "created";
	}

 

웹 POST 요청 바디의 JSON객체가 ItemCreateDto에 제대로 바인딩되는지 확인하고 싶습니다.

간단한 방법은 create 메서드에 println 과 같은 메서드를 추가해 콘솔에서 확인하는 겁니다. 간단하긴 하지만 영구적인 테스트 케이스를 만들기는 무리가 있습니다. create 메서드에 부작용이 추가되기도 하고 자동화된 테스트를 수행할 수도 없습니다.

 

테스트하기에 앞서 @RequestBody에 대해서 살펴봅시다.

메스드 파라미터 앞에 사용되어 요청 바디가 여기에 바인딩 될것이다~ 라고 마킹하는 용도의 애너테이션입니다.

 

요청 바디의 데이터가 파리미터에 전달되기 전에 HttpMessageConverter를 거친다고 하네요.

 

HttpMessageConverters 도 살펴봅시다.

 

HttpMessageConverters는 HttpMessageConverter들을 모아놓은 편의 클래스입니다.

실제 런타임에 등록된 컨터버들을 확인해볼까요?

@SpringBootTest
public class ItemRestControllerTest {

	@Autowired
	private HttpMessageConverters converters;

	@Test
	public void notNull() {
		assertThat(converters).isNotNull();
		converters.getConverters().stream()
				.forEach(c -> System.out.println(c.getClass()));
	}
}

 

class org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration$ResourceSupportHttpMessageConverter
class org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration$ResourceSupportHttpMessageConverter
class org.springframework.data.rest.webmvc.convert.UriListHttpMessageConverter
class org.springframework.http.converter.ByteArrayHttpMessageConverter
class org.springframework.http.converter.StringHttpMessageConverter
class org.springframework.http.converter.StringHttpMessageConverter
class org.springframework.http.converter.ResourceHttpMessageConverter
class org.springframework.http.converter.ResourceRegionHttpMessageConverter
class org.springframework.http.converter.xml.SourceHttpMessageConverter
class org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter
class org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
class org.springframework.data.rest.webmvc.alps.AlpsJsonHttpMessageConverter
class org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
class org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter

위와 같은 컨버터들이 등록되어 사용된다는 걸 알 수 있습니다.

우리는 JSON 객체의 바인딩에 관심있으므로 관련 클래스를 살펴봅시다. MappingJackson2HttpMessageConverter 가 보이네요. @RequestBody를 이용해 JSON 데이터를 객체에 바인딩할 때 MappingJackson2HttpMessageConverter 객체가 사용됩니다.(사실 구글 검색을 통해서 확인할 수도 있습니다)

 

MappingJackson2HttpMessageConverter가 사용된다는 걸 알았으니 전체 MVC 흐름 위에서 테스트를 작성하는게 아닌, 고립된 범위에서 테스트를 작성할 수 있을 것 같습니다.

 

	@Test
	public void create_파라미터_바인딩테스트() throws Exception {
		List<ItemDetailDto> details = new ArrayList<>();
		details.add(new ItemDetailDto("tag","content"));
		ItemCreateDto createDto = ItemCreateDto.builder()
				.name("name")
				.price(1000)
				.stockQuantity(1000)
				.details(details).build();

		MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(new ObjectMapper());
		Object ret =  converter.read(ItemCreateDto.class, new MockHttpInputMessage(gson.toJson(createDto).getBytes()));
		ItemCreateDto bindedDto = (ItemCreateDto) ret;
		assertThat(bindedDto.getName()).isEqualTo("name");
		assertThat(bindedDto.getPrice()).isEqualTo(1000);
		assertThat(bindedDto.getStockQuantity()).isEqualTo(1000);
		assertThat(bindedDto.getDetails()).isEqualTo(details);
	}

 

MappingJackson2HttpMessageConverter api는 ObjectMapper와 유사합니다. ObjectMapper 관련글을 참고하세요.

또 하나의 특이사항은 MockHttpInputMessage를 사용해 mock http 메세지를 만든 점입니다.

 

 

성공~

 

실제로 요청을 날려 돌아가는지 확인해볼까요?

 

잘 동작하네요~

 

Comments