Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Autowired MessageSource null in @ControllerAdvice unit testing controller

I have added the setHandlerExceptionResovlers to my builder and that works well except the exceptionhandler bean has autowired MessageSource and when unit testing this is null. I assume it might be cause of having to manually setup the exception handler in test. The flow is calling the controller with invalid parm, the controller calls the exception handler with a BindException.

   @RunWith(SpringJUnit4ClassRunner.class)
    @SpringApplicationConfiguration(classes = AutoControllerTest.TestContextConfiguration.class)
    @WebAppConfiguration
    public class AutoControllerTest {
        @Mock
        private AutoFacade policyFacade;

        @Mock
        private MessageSource messageSource;

        @Mock
        private RestExceptionProcessor processor;

        @InjectMocks
        private AutoController policyController;

        private MockMvc mockMvc;

        String validPolicyNbr;
        String tooLongPolicyNbr;
        AutoPolicy autoPolicy;

        @Before
        public void setUp() {
            MockitoAnnotations.initMocks(this);

            this.mockMvc = MockMvcBuilders.standaloneSetup(policyController)
                    .setHandlerExceptionResolvers(createExceptionResolver())
                    .build();


            tooLongPolicyNbr = new String("000000000000000000000000");
            validPolicyNbr = new String("4239326");
            autoPolicy = new AutoPolicy();
        }

        private ExceptionHandlerExceptionResolver createExceptionResolver() {
            ExceptionHandlerExceptionResolver exceptionResolver = new ExceptionHandlerExceptionResolver() {
                protected ServletInvocableHandlerMethod getExceptionHandlerMethod(HandlerMethod handlerMethod, Exception exception) {
                    Method method = new ExceptionHandlerMethodResolver(RestExceptionProcessor.class).resolveMethod(exception);
              // Changed     return new ServletInvocableHandlerMethod(new 
    //RestExceptionProcessor(), method);
    //Changed to resolve question 
       return new ServletInvocableHandlerMethod(new RestExceptionProcessor(messageSource), method);
                }
            };
    //Added to resolve question 
                 exceptionResolver.getMessageConverters().add(
                    new MappingJackson2HttpMessageConverter());
    //Finish
            exceptionResolver.afterPropertiesSet();
            return exceptionResolver;
        }



        @Test
        public void getPolicyDetails_TooLongPolicyNbr_ReturnsDetails() throws Exception {
                 /** Removed **/
               // MessageSource ms = messageSource;       
               // processor.setMessageSource(ms);

            this.mockMvc.perform(get("/policies/policy/{policyNbr}", tooLongPolicyNbr))
                .andDo(print())
                .andExpect(status().isOk());
        }

        @EnableAutoConfiguration
        @ComponentScan(basePackages = { "com.api" })
        @Configuration
        static public class TestContextConfiguration {
            //Removed   
            //@Bean
            //public MessageSource messageSource() {
                //return Mockito.mock(MessageSource.class);
            //}
            //Removed End
      //Added

        @Bean
    public MessageSource messageSource() {

        final ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
    messageSource.setBasenames( "classpath:messages"  );
    messageSource.setDefaultEncoding( "UTF-8" );
    messageSource.setCacheSeconds( 60 );
    messageSource.setFallbackToSystemLocale( false );
    return messageSource;           
    }
        //Added end
            @Bean
            public AutoFacade policyFacade() {
                return Mockito.mock(AutoFacade.class);
            }

            @Bean
            public HttpServletRequest request() {
                return Mockito.mock(HttpServletRequest.class);
            }

            @Bean
            public RestExceptionProcessor processor() {
                return Mockito.mock(RestExceptionProcessor.class);
            }

        }
    }




     @ControllerAdvice
        public class RestExceptionProcessor {
            private static final Logger logger = LoggerFactory.getLogger(RestExceptionProcessor.class);

            @Autowired
            private MessageSource messageSource;

            //Removed
            //public void setMessageSource(MessageSource ms){
              //      this.messageSource = ms;
            //    }
            //Added
                public RestExceptionProcessor(MessageSource messageSource) {
        super();
        this.messageSource = messageSource;
        }

        public RestExceptionProcessor() {
        super();
          }



        @ExceptionHandler({BindException.class})
            @ResponseStatus(value=HttpStatus.BAD_REQUEST)
            @ResponseBody
            public APIStatus validationError(BindException ex) {

                int statusCd = Integer.parseInt(HttpStatus.BAD_REQUEST.toString());
                String statusMessage = messageSource.getMessage("bad.request.status.msg.400", null, Locale.US);

                String errorURL = null;
                int errorCode =  400000;
                String errorType = messageSource.getMessage("bad.request.error.type.400", null, Locale.US);
                List<FieldError> fieldErrors = ex.getBindingResult().getFieldErrors();      
                List<com.fbitn.api.errors.FieldError> apiFieldErrors = new ArrayList<com.fbitn.api.errors.FieldError>();

                for (FieldError fieldError: fieldErrors) {
                    String errorMessage =  messageSource.getMessage(fieldError, Locale.US);
                    com.fbitn.api.errors.FieldError apiFieldError = new com.fbitn.api.errors.FieldError(fieldError.getField(), errorMessage);
                    apiFieldErrors.add(apiFieldError);
                }
                APIError apiError = new APIError(errorCode, errorType, "Validation Error", apiFieldErrors);
                List<APIError> errorInfoList = new ArrayList<APIError>();
                errorInfoList.add(apiError);    

                return new APIStatus(statusCd, errorURL, statusMessage, errorInfoList);
            }   
like image 760
Justin Cox Avatar asked Nov 09 '22 17:11

Justin Cox


1 Answers

I had to manually register the MessageSource in my test configs and create a constructor in the ControllerAdvice to add parm MeasageSource. Also had an issue with MessageConverter not being found for my JSON response, had to set the convert in ExceptionHandlerExceptionResolver. Edited my question to show the reflected changes.

like image 67
Justin Cox Avatar answered Nov 15 '22 12:11

Justin Cox