2013-03-08 161 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