Spring MVC 控制器单元测试不调用@ControllerAdvice

问题描述 投票:0回答:14

我在应用程序中有一组控制器和一个注释为

@ControllerAdvice
的类,它设置每个控制器中使用的某些数据元素。我正在使用
Spring MVC 3.2
并为这些控制器提供了 Junits。当我运行 Junit 时,控件不会转到
ControllerAdvice
类,如果我在
Tomcat
中部署应用程序并通过浏览器提交请求,它可以正常工作。

请问有什么想法吗?

spring spring-mvc junit
14个回答
147
投票

使用@eugene-to和另一个类似的答案后here我发现了局限性并在Spring上提出了一个问题:https://github.com/spring-projects/spring-framework/issues/17348

因此,Spring 测试在 4.2 中引入了在构建器中注册

@ControllerAdvice
类的功能。如果您使用 Spring Boot 那么您将需要 1.3.0 或更高版本。

通过这一改进,如果您使用独立设置,则可以设置一个或多个

ControllerAdvice
实例,如下所示:

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

注意:名称

setControllerAdvice()
可能不会立即显而易见,但您可以向它传递许多实例,因为它具有 var-args 签名。


42
投票

假设您有一个用 @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;
}

27
投票

在尝试测试用

ExceptionHandler
注释的
@ControllerAdvice
时,我遇到了类似的问题。就我而言,我必须将带有
@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
配置我的测试通过了。


21
投票

此代码对我有用:

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));
    }
}

7
投票

我已经在同一件事上挣扎了很长一段时间。 经过大量挖掘,最好的参考是 Spring 文档:

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

简而言之,如果您只是测试控制器及其方法,那么您可以使用 'standaloneSetup' 方法来创建一个简单的 Spring MVC 配置。 这将包括您用@ControllerAdvice注释的错误处理程序。

private MockMvc mockMvc;

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

// ...

要创建包含错误处理程序的更完整的 Spring MVC 配置,您应该使用以下设置: @RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration("test-servlet-context.xml") public class AccountTests { @Autowired private WebApplicationContext wac; private MockMvc mockMvc; @Autowired private AccountService accountService; // ... }



4
投票
ControllerAdvice

应该由

@WebMvcTest
拾取,另请参阅
Spring-Doc
到目前为止对我有用。 示例:

@RunWith(SpringRunner.class) @WebMvcTest(ProductViewController.class)



2
投票
https://github.com/spring-projects/spring-boot/issues/12979

. 您可以通过@Import注释显式告诉spring使用控制器建议:

@WebMvcTest(controllers = AppController.class) @Import(AppControllerAdvice.class) class AppControllerTest { @Autowired private MockMvc mockMvc; }



1
投票

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

以下是测试的弹簧配置

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



1
投票
spock

(groovy) 编写控制器测试时遇到了这个问题。我的测试类最初是这样写的: @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 模拟解决了问题。

@AutoConfigureMockMvc(secure = false) @SpringBootTest @Category(RestTest) class FooControllerTest extends Specification { @AutowiredMock FooService FooService @Autowired MockMvc mockMvc



0
投票

尝试将以下内容添加到您的测试 applicationContext.xml (或等效的 spring 配置文件,如果您使用的话)。

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

或者,您可能需要通过在测试类之前包含以下注释来“手动”加载测试中的上下文:

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

祝你好运!


0
投票

尝试以下方法:

https://github.com/spring-projects/spring-framework/blob/master/spring-test/src/test/java/org/springframework/test/web/servlet/samples/standalone /AsyncTests.java


0
投票

我必须改变这一点

@AutoConfigureMockMvc @ContextConfiguration(classes = OrderController.class) @WebMvcTest class OrdersIntegrationTest

对此:

@AutoConfigureMockMvc @ContextConfiguration(classes = {OrderController.class, OrdersExceptionHandler.class}) @WebMvcTest class OrdersIntegrationTest



0
投票

@WebMvcTest @ContextConfiguration(classes = { UserEndpoint.class, //the controller class for test WebConfiguration.class, //security configurations, if any StandardRestExceptionInterpreter.class. //<-- this is the ControllerAdvice class }) @WithMockUser(username = "[email protected]", authorities = {"DEFAULT"}) @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class UserEndpointTests { @Test @Order(3) public void shouldThrowExceptionWhenRegisteringDuplicateUser() throws Exception { //do setup... Mockito.doThrow(EntityExistsException.class).when(this.userService).register(user); this.mockMvc .perform(MockMvcRequestBuilders .post("/users") .contentType(MediaType.APPLICATION_JSON) .content(this.objectMapper.writeValueAsString(user))) .andDo(MockMvcResultHandlers.print()) .andExpect(MockMvcResultMatchers.status().isConflict()); } }



-1
投票

@RunWith(SpringRunner.class) @SpringBootTest(classes = {MyController.class, MyControllerAdvice.class}) @AutoConfigureMockMvc(secure = false) @ContextConfiguration(classes = {MyTestConfig.class}) @EnableWebMvc

	
© www.soinside.com 2019 - 2024. All rights reserved.