使用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(); }