使用MockMVC在JUnitTest中注册@ControllerAdvice注释控制器

我的@ControllerAdvice注释控制器如下所示:

 @ControllerAdvice public class GlobalControllerExceptionHandler { @ResponseStatus(value = HttpStatus.UNAUTHORIZED) @ExceptionHandler(AuthenticationException.class) public void authenticationExceptionHandler() { } } 

当然我的开发是测试驱动的,我想在JUnit测试中使用我的exceptionHandler。 我的测试用例如下:

 public class ClientQueriesControllerTest { private MockMvc mockMvc; @InjectMocks private ClientQueriesController controller; @Mock private AuthenticationService authenticationService; @Before public void setup() { MockitoAnnotations.initMocks(this); mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); } @Test public void findAllAccountRelatedClientsUnauthorized() throws Exception { when(authenticationService.validateAuthorization(anyString())).thenThrow(AuthenticationException.class); mockMvc.perform(get("/rest/clients").header("Authorization", UUID.randomUUID().toString())) .andExpect(status().isUnauthorized()); } } 

可能我需要注册ControllerAdvice类。 怎么做?

为了激活完整的Spring MVC配置,您需要使用MockMvcBuilders.webAppContextSetup而不是MockMvcBuilders.standaloneSetup

有关更多详细信息,请查看Spring文档的这一部分。

您的代码如下所示:

 @RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration("test-config.xml") public class ClientQueriesControllerTest { private MockMvc mockMvc; @Autowired private WebApplicationContext webApplicationContext; @Autowired private AuthenticationService authenticationService; @Before public void setup() { MockitoAnnotations.initMocks(this); mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); } @Test public void findAllAccountRelatedClientsUnauthorized() throws Exception { when(authenticationService.validateAuthorization(anyString())).thenThrow(AuthenticationException.class); mockMvc.perform(get("/rest/clients").header("Authorization", UUID.randomUUID().toString())) .andExpect(status().isUnauthorized()); } } 

然后在test-config.xml添加一个用于AuthenticationService的Spring bean,它是一个mock。

    

如果要重用常规的Spring配置文件而不是创建test-config.xml您当然可以使用配置文件在测试中注入模拟AuthenticationService


UPDATE

在挖掘了一下之后,我发现( MockMvcBuilders.standaloneSetup )返回的StandaloneMockMvcBuilder是完全可定制的。 这意味着您可以插入您喜欢的任何exception解析器。

但是,由于您使用的是@ControllerAdvice ,因此下面的代码将无效。 但是,如果您的@ExceptionHandler方法位于同一个控制器中,则您需要更改的代码如下:

 mockMvc = MockMvcBuilders.standaloneSetup(controller).setHandlerExceptionResolvers(new ExceptionHandlerExceptionResolver()).build(); 

更新2

当你还使用@ControllerAdvice时,更多的挖掘给出了如何注册正确的exception处理程序的答案。

您需要将测试中的设置代码更新为以下内容:

  @Before public void setUp() throws Exception { final ExceptionHandlerExceptionResolver exceptionHandlerExceptionResolver = new ExceptionHandlerExceptionResolver(); //here we need to setup a dummy application context that only registers the GlobalControllerExceptionHandler final StaticApplicationContext applicationContext = new StaticApplicationContext(); applicationContext.registerBeanDefinition("advice", new RootBeanDefinition(GlobalControllerExceptionHandler.class, null, null)); //set the application context of the resolver to the dummy application context we just created exceptionHandlerExceptionResolver.setApplicationContext(applicationContext); //needed in order to force the exception resolver to update it's internal caches exceptionHandlerExceptionResolver.afterPropertiesSet(); mockMvc = MockMvcBuilders.standaloneSetup(controller).setHandlerExceptionResolvers(exceptionHandlerExceptionResolver).build(); } 

从Spring 4.2开始,您可以将ControllerAdvice直接注册到StandaloneMockMvcBuilder中:

 MockMvcBuilders .standaloneSetup(myController) .setControllerAdvice(new MyontrollerAdvice()) .build(); 

通过以下解决方案超越了NestedServletException …

  final StaticApplicationContext applicationContext = new StaticApplicationContext(); applicationContext.registerSingleton("exceptionHandler", GlobalControllerExceptionHandler.class); final WebMvcConfigurationSupport webMvcConfigurationSupport = new WebMvcConfigurationSupport(); webMvcConfigurationSupport.setApplicationContext(applicationContext); mockMvc = MockMvcBuilders.standaloneSetup(controller). setHandlerExceptionResolvers(webMvcConfigurationSupport.handlerExceptionResolver()). build(); 

您可以将其添加到测试类中

 @Autowired @Qualifier("handlerExceptionResolver") void setExceptionResolver(HandlerExceptionResolver resolver) { this.exceptionResolver = resolver; } 

然后将exceptionResolver添加到您的MockMvc

 @Before public void setup() { MockitoAnnotations.initMocks(this); mockMvc = MockMvcBuilders.standaloneSetup(controller) .setHandlerExceptionResolvers(this.exceptionResolver).build(); }