컨트롤러의 테스트 코드를 작성하는데 의존 관계 문제로 예외가 발생하였다.
우리 프로젝트에서는 공통 응답 메시지를 BaseController라는 부모 클래스에서 처리하고,
모든 Controller 는 BaseController클래스를 상속받아 응답 메시지 처리 메서드를 호출하여 응답 값으로 변환하였다.
때문에 Controller에서는 필요하지 않은 의존성이지만 BaseController에서 공통 응답 메시지 처리를 위해 필요로 하는 의존성때문에 예외가 발생한 것이다.
테스트 코드가 신호를 보냈기 때문에 HandlerMethodReturnValueHandler 확장하여 공통 응답 메시지를 처리하는 관심사를 컨트롤에서 분리하고 컨트롤러의 상속을 제거하여 문제를 해결하였다.
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ResponseStatus
public @interface ApiResponseBody {
}
@Setter
public class ApiResponseResolver implements HandlerMethodReturnValueHandler {
private RequestResponseBodyMethodProcessor requestResponseBodyMethodProcessor;
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return (AnnotatedElementUtils.hasAnnotation(
returnType.getContainingClass(), ApiResponseBody.class) ||
returnType.hasMethodAnnotation(ApiResponseBody.class));
}
@Override
public void handleReturnValue(Object returnValue,
MethodParameter returnType,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest) throws Exception {
// 공통 응답 메시지 처리 로직
// ...
requestResponseBodyMethodProcessor.handleReturnValue(responseDto,
returnType,
mavContainer,
webRequest);
}
}
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {
handlers.add(new ApiResponseResolver());
}
@Override
public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
RequestResponseBodyMethodProcessor requestResponseBodyMethodProcessor = null;
ApiResponseResolver apiResponseResolver = null;
for (HandlerExceptionResolver resolver : resolvers) {
if (resolver instanceof ExceptionHandlerExceptionResolver exceptionHandlerExceptionResolver) {
HandlerMethodReturnValueHandlerComposite handlerMethodReturnValueHandlerComposite = exceptionHandlerExceptionResolver.getReturnValueHandlers();
if (handlerMethodReturnValueHandlerComposite == null) {
continue;
}
for (HandlerMethodReturnValueHandler handler : handlerMethodReturnValueHandlerComposite.getHandlers()) {
if (handler instanceof RequestResponseBodyMethodProcessor processor) {
requestResponseBodyMethodProcessor = processor;
}
if (handler instanceof ApiResponseResolver responseResolver) {
apiResponseResolver = responseResolver;
}
}
if (apiResponseResolver != null) {
apiResponseResolver.setRequestResponseBodyMethodProcessor(requestResponseBodyMethodProcessor);
}
}
}
}
}
컨트롤러에서 공통 응답 메시지 처리 관심사를 ReturnValueHandler를 확장하여 분리하였고, 이로 인해서 부모 클래스와의 결합을 제거하였고 컴포넌트간의 결합도를 낮출 수 있었다.