@ControllerAdvice 单元测试控制器中的自动装配 MessageSource null
Autowired MessageSource null in @ControllerAdvice unit testing controller
我已经将 setHandlerExceptionResovlers 添加到我的构建器中并且效果很好,除了异常处理程序 bean 具有自动装配的 MessageSource 并且在单元测试时这是空的。我认为这可能是必须在测试中手动设置异常处理程序的原因。流程使用无效参数调用控制器,控制器使用 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);
}
我不得不在我的测试配置中手动注册 MessageSource,并在 ControllerAdvice 中创建一个构造函数来添加参数 MeasageSource。我的 JSON 响应未找到 MessageConverter 也有问题,必须在 ExceptionHandlerExceptionResolver 中设置转换。编辑我的问题以显示反映的更改。
我已经将 setHandlerExceptionResovlers 添加到我的构建器中并且效果很好,除了异常处理程序 bean 具有自动装配的 MessageSource 并且在单元测试时这是空的。我认为这可能是必须在测试中手动设置异常处理程序的原因。流程使用无效参数调用控制器,控制器使用 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);
}
我不得不在我的测试配置中手动注册 MessageSource,并在 ControllerAdvice 中创建一个构造函数来添加参数 MeasageSource。我的 JSON 响应未找到 MessageConverter 也有问题,必须在 ExceptionHandlerExceptionResolver 中设置转换。编辑我的问题以显示反映的更改。