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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15302243/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 05:48:13  来源:igfitidea点击:

Spring MVC Controllers Unit Test not calling @ControllerAdvice

springspring-mvcjunit

提问by Arun

I have a set of Controllers in the application and a class annotated as @ControllerAdvicewhich sets up certain data elements that are used in each of these controllers. I'm using Spring MVC 3.2and have Junits for these controllers. When I run the Junit the control is not going to the ControllerAdviceclass wheres it works fine if I deploy the app in Tomcatand submit a request through browser.

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

Any thoughts please?.

请问有什么想法吗?

回答by Matt Byrne

After using the answer from @eugene-to and another similar one hereI found limitations and raised an issue on Spring: https://jira.spring.io/browse/SPR-12751

使用答案来自@尤金到和其他类似的一个后,在这里我找到了限制,并在春季提出的一个问题:https://jira.spring.io/browse/SPR-12751

As a result, Spring test introduced the ability to register @ControllerAdviceclasses in the builder in 4.2. If you are using Spring Bootthen you will need 1.3.0 or later.

因此,Spring test@ControllerAdvice在 4.2 中引入了在构建器中注册类的能力。如果您使用的是Spring Boot,那么您将需要 1.3.0 或更高版本。

With this improvement, if you are using standalone setup then you can set one or more ControllerAdviceinstances like so:

通过这一改进,如果您使用的是独立设置,那么您可以ControllerAdvice像这样设置一个或多个实例:

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

Note:the name setControllerAdvice()may not make it immediately obvious but you can pass many instances to it, since it has a var-args signature.

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

回答by Eugene To

Suppose you have class MyControllerAdvice annotated with @ControllerAdvice that has methods annotated with @ExceptionHandler. For MockMvc you can easily add this class as exception resolver.

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

回答by tunguski

I had similar problem when trying to test ExceptionHandlerannotated with @ControllerAdvice. In my case I had to add @Configurationfile with @EnableWebMvcannotation to @ContextConfigurationon test class.

试图测试,当我有类似的问题ExceptionHandler与注解@ControllerAdvice。在我的情况下,我必须在测试类中添加@Configuration带有@EnableWebMvc注释的文件@ContextConfiguration

So my test looked like this:

所以我的测试是这样的:

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

With @EnableWebMvcconfiguration my test passed.

通过@EnableWebMvc配置,我的测试通过了。

回答by Bikesh M

This is working for me

这对我有用

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

    }

}

回答by Neil D

I've been struggling with the same thing for quite some time. After much digging, the best reference was the Spring documentation:

很长一段时间以来,我一直在为同样的事情苦苦挣扎。经过大量挖掘,最好的参考是 Spring 文档:

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

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

In short, if you are simply testing a controller and its methods then you can use the 'standaloneSetup'method which creates a simple Spring MVC configuration. This will notinclude your error handler that you annotate with @ControllerAdvice.

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

private MockMvc mockMvc;

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

// ...

To create a more complete Spring MVC configuration that doescontain your error handler you should use the following setup:

要创建一个更完整的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;

    // ...

}

回答by Mustafa

I encountered this issue while writing controller tests with spock(groovy). My test class was originally written like:

我在用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()
....
}

This caused ControllerAdvice to be ignored. Changing the code to to Autowire the mocks fixed the problem.

这导致 ControllerAdvice 被忽略。将代码更改为 Autowire 模拟解决了问题。

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

  @AutowiredMock
  FooService FooService

  @Autowired
  MockMvc mockMvc

回答by himanshu

@tunguski sample code works but it pays to understand how things work. This is just one way to set things up.

@tunguski 示例代码有效,但了解事情的工作原理是值得的。这只是一种设置方式。

@EnableWebMvcis equivalent to following in a spring configuration file

@EnableWebMvc相当于在spring配置文件中跟随

<mvc:annotation-driven />

<mvc:annotation-driven />

Essentially for things to work you need to initialize Spring Mvc and load all your controllers and bean references. So following could be a valid setup as well as an alternate

本质上,为了工作,您需要初始化 Spring Mvc 并加载所有控制器和 bean 引用。所以以下可能是一个有效的设置以及替代

Following is how you would setup the test class

以下是您将如何设置测试类

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

And following could be the spring configuration for the test

以下可能是测试的弹簧配置

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

回答by Eddy

I suspect you need to use asyncDispatch in your test; the regular testing framework is broken with asynchronous controllers.

我怀疑您需要在测试中使用 asyncDispatch;异步控制器破坏了常规测试框架。

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

尝试以下方法:https: //github.com/spring-projects/spring-framework/blob/master/spring-test/src/test/java/org/springframework/test/web/servlet/samples/standalone/AsyncTests .java

回答by Michael Hegner

The ControllerAdviceshould be picked up by @WebMvcTest, see also Spring-DocWorks so far for me.

ControllerAdvice应有所回升@WebMvcTest,又见春天督至今对我的作品。

Example:

例子:

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

回答by Liam

You would need to provide more info, and maybe some actual code and/or config files, before you can expect specific answers. That said, based on the little you have provided, it sounds like the annotated bean is not being loaded.

您需要提供更多信息,也许还有一些实际的代码和/或配置文件,然后才能得到具体的答案。也就是说,根据您提供的一点信息,听起来好像没有加载带注释的 bean。

Try adding the following to your test applicationContext.xml (or equivalent spring config file, if you are using one).

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

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

Alternatively, you may need to 'manually' load the contexts within the tests by including the following annotations before your test class:

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

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

Good luck!

祝你好运!