2014-09-01 87 views
19

@ControllerAdvice註解控制器是這樣的:註冊@ControllerAdvice註解控制器在JUnitTest與MockMVC

@ControllerAdvice 
public class GlobalControllerExceptionHandler { 

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

當然,我的開發測試驅動,我想用我的異常處理程序的JUnit測試。我的測試情況是這樣的:

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類。怎麼做?

+0

您是否試過'MockMvcBuilders.webAppContextSetup'選項,如http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/testing.html#spring-mvc-test-框架而不是'MockMvcBuilders.standaloneSetup'? – geoand 2014-09-01 10:57:54

回答

20

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

檢查出this 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您將添加一個Spring bean的AuthenticationService這是一個模擬。

​​

你當然可以使用配置文件注入在測試中模擬AuthenticationService如果要重用,而不是創建test-config.xml你經常Spring配置文件。


UPDATE

了一下週圍挖後,我發現,通過(MockMvcBuilders.standaloneSetup)返回StandaloneMockMvcBuilder是完全可定製的。這意味着你可以插入你喜歡的任何異常解析器。

但是由於您使用的是@ControllerAdvice,下面的代碼將不起作用。 然而,如果你的@ExceptionHandler方法是相同的控制器內的代碼你就必須改變如下:

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

更新2

一些更多的挖給出了答案如何你當您也使用@ControllerAdvice時,可以註冊一個正確的異常處理程序。

您需要更新測試設置代碼爲以下:

@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(); 
    } 
+0

感謝您的文章,它幫助了很多。但是有沒有比webApplicationContext更簡單的解決方案?我試圖直接註釋類AuthenticationException,它可以與standaloneserver一起使用。問題是我想從服務層分離其餘的層,而不是將兩個層與來自另一層的註釋混合在一起。異常處理應該在其餘層進行管理。還有其他可能嗎? – 2014-09-01 11:48:23

+0

@RudolfSchmidt我很高興它幫助你!你想分開顧慮是正確的!但我不明白'webApplicationContext'是什麼問題。你能詳細解釋一下嗎?我不知道有任何其他解決方案可以在測試環境中正確註冊異常處理 – geoand 2014-09-01 11:57:03

+0

@RudolfSchmidt我發現了一些可能有所幫助的更多信息。不久將更新 – geoand 2014-09-01 12:03:49

18

了過去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(); 
+0

感謝您的回答!基於它,我發現自己的RestAssuredMockMvc方法的解決方案:http://stackoverflow.com/a/38435008/2239713 – ilyailya 2016-07-26 12:52:11

-1

您可以將它添加到您的測試類

@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(); 
} 
+1

對我來說,在獨立模式下使用@Autowired似乎沒有意義。你甚至不應該在獨立模式下有一個彈簧環境 – 2016-01-26 09:53:30

20

從Spring 4.2,您可以將您的ControllerAdvice直接註冊到您的StandaloneMockMvcBuilder :

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

不錯,比以前的解決方案簡單得多。 – 2017-06-09 18:29:11