首页 > 解决方案 > MockMvc 和 @ControllerAdvice 在测试中不起作用

问题描述

我正在测试我RestControllermockMvc. 我有一个全局RestExceptionHandler来解决所有异常。在我的RestController我抛出Exception RequestValidationException这样的自定义:

    @ApiOperation("Search something")
    @RequestMapping(path = "/search", method = RequestMethod.POST)
    public CompletableFuture<SomeResponse> search(
            @RequestBody @Validated SearchRequest request, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            throw new RequestValidationException(bindingResult);
        }
        return searchService.search(request);
    }

当我通过空请求时,它必须抛出 RequestValidationException(bindingResult)

但是当我开始测试时,它们会落在我抛出的那个地方Exception来解决它。

我尝试mockMvc像这样配置我:

@RunWith(SpringRunner.class)
public class SearchControllerTest {
    private MockMvc mockMvc;

    @InjectMocks
    protected SearchController searchController;

    @MockBean
    private SearchService searchService;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        this.mockMvc = MockMvcBuilders.standaloneSetup(searchController)
                .setHandlerExceptionResolvers(getHandlerExceptionResolver())
                .build();
    }

  private HandlerExceptionResolver getHandlerExceptionResolver() {
        final StaticApplicationContext applicationContext = new StaticApplicationContext();
        applicationContext.registerSingleton("exceptionHandler", RestExceptionHandler.class);

        final WebMvcConfigurationSupport webMvcConfigurationSupport = new WebMvcConfigurationSupport();
        webMvcConfigurationSupport.setApplicationContext(applicationContext);
        return webMvcConfigurationSupport.handlerExceptionResolver();
    }

但它没有帮助。我收到一个Exception带有消息的 insted json。

我的RequestValidationExceptionHandler

@Component
public class RequestValidationExceptionHandler implements ApiExceptionHandler {

    @Override
    public ResponseEntity<ApiResponse> process(Throwable throwable) {
        RequestValidationException e = (RequestValidationException) throwable;

        if (e.getBindingResult() != null) {
            return new ResponseEntity<>(ApiResponse.badRequest(e.getBindingResult()), HttpStatus.OK);
        }

        return new ResponseEntity<>(ApiResponse.badRequest(throwable, ApiResponseCode.BAD_REQUEST), HttpStatus.OK);
    }

    @Override
    public Class<? extends Throwable> getSupportedException() {
        return RequestValidationException.class;
    }
}

2)我的@ControllerAdvice

@Slf4j
@ControllerAdvice
@SuppressWarnings({"checkstyle:JavadocMethod", "checkstyle:MultipleStringLiterals"})
public class RestExceptionHandler {

    @Autowired
    private ExceptionHandlerRegistry handlerRegistry;

    @ExceptionHandler
    public ResponseEntity handleThrowable(Throwable throwable, WebRequest request) {
        request.setAttribute(Constants.ERROR_ATTRIBUTE_NAME, throwable, RequestAttributes.SCOPE_REQUEST);

        Throwable ex = throwable instanceof CompletionException ?
                ObjectUtils.defaultIfNull(throwable.getCause(), throwable) : throwable;

        for (ApiExceptionHandler handler : handlerRegistry.getHandlers()) {
            if (handler.isSupported(ex)) {
                return handler.process(ex);
            }
        }

        return new ResponseEntity<>(ApiResponse.badRequest(throwable, ApiResponseCode.SERVER_ERROR), HttpStatus.OK);
    }
}

3)和ExceptionHandlerRegistry

@Component
public class ExceptionHandlerRegistry {

    @Getter
    private final List<ApiExceptionHandler> handlers;

    @Autowired
    public ExceptionHandlerRegistry(List<ApiExceptionHandler> handlers) {
        this.handlers = ObjectUtils.defaultIfNull(handlers, Collections.emptyList());
    }
}

错误消息: org.springframework.web.util.NestedServletException: Request processing failed; nested exception is ru.filit.mvideo.mb2c.api.exceptions.RequestValidationException

更新 所以在与@MichaelMichailidis 讨论之后,我尝试这样做,我只是添加了一个带有所需bean 的内部@Configuration 类:


    @TestConfiguration
    static class SearchControllerTestConfiguration {

        @Bean
        public RequestValidationExceptionHandler requestValidationExceptionHandler(){
            return new RequestValidationExceptionHandler();
        }

        @Bean
        public ExceptionHandlerRegistry getExceptionHandlerRegistry(final RequestValidationExceptionHandler requestValidationExceptionHandler){
            return new ExceptionHandlerRegistry(Collections.singletonList(requestValidationExceptionHandler));
        }

        @Bean
        public RestExceptionHandler getRestExceptionHandler(){
            return new RestExceptionHandler();
        }
    }

和我的测试通过。但是我不明白为什么在我添加@ControllerAdvice 之前测试在没有配置的情况下工作?

标签: javaspring-bootmockmvccontroller-advice

解决方案


您可以尝试在测试类中导入异常处理程序:

@RunWith(SpringRunner.class)
@Import(RestExceptionHandler.class)  // EXCEPTION HANDLER CLASS
public class SearchControllerTest {

推荐阅读