使用 MockMVC 在 JUnitTest 中注册带注释@ControllerAdvice控制器

2022-09-01 14:58:50

我的带注释的控制器如下所示:@ControllerAdvice

@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


答案 1

从 Spring 4.2 开始,您可以将 ControllerAdvice 直接注册到 StandaloneMockMvcBuilder 中:

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

答案 2

为了激活完整的Spring MVC配置,您需要使用 代替 .MockMvcBuilders.webAppContextSetupMockMvcBuilders.standaloneSetup

查看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.xmlAuthenticationService

<bean id="authenticationService" class="org.mockito.Mockito" factory-method="mock">
    <constructor-arg value="your.package.structure.AuthenticationService"/>
</bean>

当然,如果您想重用常规的Spring配置文件而不是创建,则可以使用配置文件在测试中注入模拟。AuthenticationServicetest-config.xml


更新

经过一番挖掘,我发现返回的()是完全可定制的。这意味着您可以插入您喜欢的任何异常解析器。StandaloneMockMvcBuilderMockMvcBuilders.standaloneSetup

但是,由于您正在使用 ,下面的代码将不起作用。但是,如果您的方法位于同一控制器中,则只需更改以下代码:@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();
    }

推荐