spring-boot라면 이러지 말았어야 ^^
@IntegrationTest를 이용한 spring-boot integration test시 request body에 해당하는 POJO에 default constructor가 없으면 테스트 대상 메소드가 아예 호출이 안된다. 오류 메시지도 없이...
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@IntegrationTest({ "server.port=0" })
public class ArticleControllerIntegrationTest {
@Value("${local.server.port}")
private int port;
private RestTemplate template;
@Before
public void setUp() throws Exception {
template = new TestRestTemplate();
}
@Test
public void write_article() {
final String writeArticleUri = "http://localhost:" + port + "/articles";
WriteArticleRequest requestModel = new WriteArticleRequest("title01", "content01");
WriteArticleViewModel viewModel = template.postForObject(writeArticleUri, requestModel, WriteArticleViewModel.class);
assertThat(viewModel.id, is(notNullValue()));
assertThat(viewModel.title, equalTo(requestModel.title));
assertThat(viewModel.content, equalTo(requestModel.content));
}
}
위의 테스트 코드는 아래의 controller 메소드를 호출하기를 기대했다.
@RestController
public class ArticleController {
@Autowired
private WriteArticleInteractor interactor;
@Autowired
private WriteArticlePresenter presenter;
@RequestMapping(value = "/articles", method = RequestMethod.POST)
public WriteArticleViewModel writeArticle(@RequestBody WriteArticleRequest request) {
assert presenter != null;
assert interactor != null;
validate(request);
WriteArticleResponse response = interactor.interact(request);
WriteArticleViewModel viewModel = presenter.present(response);
viewModel.id = "1";
return viewModel;
}
...
}
그런데 @RequestBody로 지정한 WriteArticleRequest는 아래와 같이 default constructor가 없었다.
public class WriteArticleRequest implements RequestModel {
public String title;
public String content;
public WriteArticleRequest(String title, String content) {
this.title = title;
this.content = content;
}
}
이 경우 위의 ArticleController#writeArticle 메소드가 호출되지 않았다. 한참을 헤매다가 혹시 하는 마음에 WriteArticleRequest에 default constructor를 추가하였더니 그제야 제대로 호출이 되었다.
아마 문서를 잘 살펴보면 @RequestBody로 사용할 객체는 POJO Bean 규약을 준수해야 한다는 내용이 있었을지도 모르겠다. 하지만 spring-boot라면 이와 같은 경우 적절한 오류 메시지를 뿌려주었어야지 않나???
라는 생각이 강력하게 든다.
ps 위 코드는 Robert C Martin이 OOP 2015에서 언급한 Clean Architecture를 프로토타이핑하는 과정에서 작성하였다.