2013-03-08 157 views
29

我在應用程序中有一組控制器,註釋類爲@ControllerAdvice,它設置了在這些控制器中使用的某些數據元素。我正在使用Spring MVC 3.2併爲這些控制器提供Junits。當我運行Junit時,如果我在Tomcat中部署應用程序並通過瀏覽器提交請求,則控件不會去ControllerAdvice類,它可以正常工作。Spring MVC控制器單元測試不調用@ControllerAdvice

有什麼想法嗎?

+1

欣賞此更新。我遇到類似的問題,@ControllerAdvice類中的@ExceptionHandler(Exception.class)註釋方法不通過單元測試 - webAppContextSetup(wac).build()調用。在部署爲webapp時調用ExceptionHandler註釋的方法。 – kctang 2013-07-29 16:37:06

回答

0

您需要提供更多信息,並且可能需要一些實際的代碼和/或配置文件,然後才能得到特定的答案。這就是說,基於你提供的一點點,這聽起來像註釋的bean沒有被加載。

嘗試將以下內容添加到您的測試applicationContext.xml(或等效的彈簧配置文件,如果使用的話)。

<context:component-scan base-package="com.example.path.to.package" /> 

或者,您可能需要爲「手動」的包括你的測試類之前以下注釋加載測試中的語境:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration("/applicationContext.xml") 

祝你好運!

4

我一直在同一件事上掙扎了很長時間。多挖掘後,最好的參考就是Spring文檔:

http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/testing.html#spring-mvc-test-framework

總之,如果你只是測試控制器及其方法,那麼你可以使用「standaloneSetup」方法,它創建了一個簡單的Spring MVC配置。這將而不是包括您使用@ControllerAdvice註釋的錯誤處理程序。試圖測試標註有@ControllerAdviceExceptionHandler

@RunWith(SpringJUnit4ClassRunner.class) 
@WebAppConfiguration 
@ContextConfiguration("test-servlet-context.xml") 
public class AccountTests { 

    @Autowired 
    private WebApplicationContext wac; 

    private MockMvc mockMvc; 

    @Autowired 
    private AccountService accountService; 

    // ... 

} 
+0

您仍然需要初始化mockMvc,這在以上示例中未顯示: @Before public void setUp(){ mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); } – 2015-08-05 13:59:34

+1

您可以使用.setControllerAdvice(xxx)和StandaloneMockMvcBuilder來注入ControllerAdvice bean – frno 2016-09-23 15:21:09

12

我有類似的問題:

private MockMvc mockMvc; 

@Before 
public void setup() { 
    this.mockMvc = MockMvcBuilders.standaloneSetup(new AccountController()).build(); 
} 

// ... 

要建立一個更加完整的Spring MVC配置是確實包含您的錯誤處理程序,你應該使用下面的設置。在我的情況下,我必須添加@Configuration文件@EnableWebMvc註釋到@ContextConfiguration在測試類。

所以我的測試是這樣的:

@RunWith(SpringJUnit4ClassRunner.class) 
@WebAppConfiguration 
@ContextConfiguration(classes = { 
    RestProcessingExceptionHandler.class, 
    TestConfiguration.class, 
    RestProcessingExceptionThrowingController.class }) 
public class TestRestProcessingExceptionHandler { 


    private MockMvc mockMvc; 
    @Autowired 
    WebApplicationContext wac; 


    @Before 
    public void setup() { 
    mockMvc = webAppContextSetup(wac).build(); 
    } 


    @Configuration 
    // !!! this is very important - conf with this annotation 
    //  must be included in @ContextConfiguration 
    @EnableWebMvc 
    public static class TestConfiguration { } 


    @Controller 
    @RequestMapping("/tests") 
    public static class RestProcessingExceptionThrowingController { 


    @RequestMapping(value = "/exception", method = GET) 
    public @ResponseBody String find() { 
     throw new RestProcessingException("global_error_test"); 
    } 
    } 


    @Test 
    public void testHandleException() throws Exception { 
    mockMvc.perform(get("/tests/exception")) 
     .andExpect(new ResultMatcher() { 


      @Override 
      public void match(MvcResult result) throws Exception { 
      result.getResponse().getContentAsString().contains("global_error_test"); 
      } 
     }) 
     .andExpect(status().isBadRequest()); 
    } 
} 

隨着@EnableWebMvc配置我的測試通過。

+0

謝謝,您的配置工程很棒!我會獎勵賞金! – balteo 2013-09-20 09:56:43

+0

@EnableWebMvc缺席是問題,謝謝。 – raonirenosto 2014-03-23 15:53:11

+0

java.lang.IllegalStateException:無法加載ApplicationContext :( – ptimson 2016-08-04 15:46:11

36

假設你有@ControllerAdvice註解的類MyControllerAdvice,它有@ExceptionHandler註解的方法。對於MockMvc,您可以輕鬆地將此類添加爲異常解析器。

@Before 
public void beforeTest() { 
    MockMvc mockMvc = standaloneSetup(myControllers) 
     .setHandlerExceptionResolvers(createExceptionResolver()) 
     .build(); 
} 

private ExceptionHandlerExceptionResolver createExceptionResolver() { 
    ExceptionHandlerExceptionResolver exceptionResolver = new ExceptionHandlerExceptionResolver() { 
     protected ServletInvocableHandlerMethod getExceptionHandlerMethod(HandlerMethod handlerMethod, Exception exception) { 
      Method method = new ExceptionHandlerMethodResolver(MyControllerAdvice.class).resolveMethod(exception); 
      return new ServletInvocableHandlerMethod(new MyControllerAdvice(), method); 
     } 
    }; 
    exceptionResolver.afterPropertiesSet(); 
    return exceptionResolver; 
} 
+0

感謝,偉大的工程 – 2014-02-10 15:35:09

+0

按預期工作,謝謝! – aksamit 2014-02-28 12:43:18

+1

這不適用於我使用異步請求處理 – hvgotcodes 2014-10-22 19:55:21

1

@tunguski示例代碼的作品,但它支付了解事情如何工作。這只是一種設置方法。

@EnableWebMvc相當於一個Spring配置文件

<mvc:annotation-driven />

本質的東西下面的工作,你需要初始化Spring MVC和加載所有的控制器和bean引用。所以,下面可能是一個有效的參數設置以及備用

以下是你將如何設置測試類

@RunWith(SpringJUnit4ClassRunner.class) 
    @ContextConfiguration(locations = { "classpath: "classpath:test-context.xml" }) 
    @WebAppConfiguration  
    public class BaseTest { 

     @Autowired 
     WebApplicationContext wac; 

     private MockMvc mockMvc; 

     @Before 
     public void setUp() { 
      mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); 
     } 
    } 

而且下面可能是spring配置爲測試

<mvc:annotation-driven /> 
<context:component-scan base-package="com.base.package.controllers" /> 
51

後使用@ eugene-to和另一個類似的答案here我發現了限制並在Spring上提出了一個問題:https://jira.spring.io/browse/SPR-12751

因此,Spring測試引入了在4.2中在構建器中註冊@ControllerAdvice類的能力。如果您使用Spring Boot那麼您將需要1.3.0或更高版本。

通過這種改進,如果你使用的是獨立安裝程序,那麼你可以設置一個或多個ControllerAdvice情況下,像這樣:

mockMvc = MockMvcBuilders.standaloneSetup(yourController) 
      .setControllerAdvice(new YourControllerAdvice()) 
      .build(); 

注:名稱setControllerAdvice()可能不會讓它馬上顯而易見的,但你可以通過它有很多實例,因爲它有一個var-args簽名。

+0

太好了。有用。感謝 – 2016-06-13 10:39:11

+2

這應該是公認的答案 – frno 2016-09-23 15:24:03

+0

我添加的東西放入系統,像我一樣,誰被彈簧驗證上面的伎倆惱火: this.mockMvc = MockMvcBuilders.standaloneSetup(yourController) .setValidator(模擬( Validator.class)) .setControllerAdvice(new CaissierExceptionHandler()) .build(); – 2017-08-28 17:45:50

-1

這是爲我工作

public class MyGlobalExceptionHandlerTest { 

    private MockMvc mockMvc; 

    @Mock 
    HealthController healthController; 

    @BeforeTest 
    public void setUp() { 
     MockitoAnnotations.initMocks(this); 
     mockMvc = MockMvcBuilders.standaloneSetup(healthController).setControllerAdvice(new GlobalExceptionHandler()) 
      .build(); 
    } 

    @Test(groups = { "services" }) 
    public void testGlobalExceptionHandlerError() throws Exception { 

     Mockito.when(healthController.health()).thenThrow(new RuntimeException("Unexpected Exception")); 

     mockMvc.perform(get("/health")).andExpect(status().is(500)).andReturn(); 

    } 

} 
+0

什麼版本的彈簧引導可以使用?與1.5.6這個代碼永遠不會調用我的controlleradvice – 2017-09-18 05:01:35

+0

這將是明顯的最小的解決方案,但不起作用.. – Dudelilama 2018-02-19 17:18:23

0

我遇到過這個問題,而與spock(常規)寫入控制器的測試。我的測試類最初是這樣寫的:

@AutoConfigureMockMvc(secure = false) 
@SpringBootTest 
@Category(RestTest) 
class FooControllerTest extends Specification { 
    def fooService = Mock(FooService) 
    def underTest = new FooController(FooService) 
    def mockMvc = MockMvcBuilders.standaloneSetup(underTest).build() 
.... 
} 

這導致ControllerAdvice被忽略。將代碼更改爲Autowire mock修復了問題。

@AutoConfigureMockMvc(secure = false) 
@SpringBootTest 
@Category(RestTest) 
class FooControllerTest extends Specification { 

    @AutowiredMock 
    FooService FooService 

    @Autowired 
    MockMvc mockMvc