Pregunta Probando @RestController con @ControllerAdvice


Mi problema está relacionado con las pruebas de Spring @RestController, que también utiliza @ControllerAdvice con @ExceptionHandler. Aquí está el código:

Clase @ControllerAdvice:

@ControllerAdvice
public class MyAppExceptionHandler {

    @ExceptionHandler({ NoSuchEntityException.class })
    @ResponseStatus(value = HttpStatus.NOT_FOUND)
    public @ResponseBody
    ErrorDTO handleNotFoundException(Exception ex) throws IOException {

        return new ErrorDTO.Builder().setStatus(HttpStatus.NOT_FOUND)
                .setCause(ex.getClass().getName())
                .setThrowable(ex).build();
    }
}

Cuando se usa en la aplicación, todo funciona bien, obteniendo perfectamente la respuesta 404 con la explicación de JSON, pero al intentar usarlo durante las pruebas, suceden cosas malas.

Mi clase de prueba:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { WebConfig.class })
@WebAppConfiguration
public class SomeTest {

    @Mock
    private SomeService service;

    @InjectMocks
    private SomeController controller;

    private MockMvc mvc;

    private ExceptionHandlerExceptionResolver createExceptionResolver() {
        ExceptionHandlerExceptionResolver exceptionResolver = new ExceptionHandlerExceptionResolver() {
            @Override
            protected ServletInvocableHandlerMethod getExceptionHandlerMethod(
                HandlerMethod handlerMethod, Exception exception) {
                Method method = new ExceptionHandlerMethodResolver(
                        MyAppExceptionHandler.class).resolveMethod(exception);
                return new ServletInvocableHandlerMethod(
                    new MyAppExceptionHandler(), method);
            }
        };
        exceptionResolver.afterPropertiesSet();
        return exceptionResolver;
    }

    @Before
    public void setup() {

        MockitoAnnotations.initMocks(this);
        mvc = MockMvcBuilders.standaloneSetup(controller)
                .setHandlerExceptionResolvers(createExceptionResolver())
                .build();
    }

    @Test
    public void thatExceptionHappens() throws Exception {

        when(service.get(10)).thenThrow(new NoSuchEntityException(Some.class, 10));

        mvc.perform(get("/api/some/10")).andExpect(status().isNotFound());
    }
}

Al intentar ejecutarlo:

2014-07-15 19:35:01.376 [main] ERROR com.package.SomeTest$1 - Failed to invoke @ExceptionHandler method: public com.package.ErrorDTO com.package.MyAppExceptionHandler.handleNotFoundException(java.lang.Exception) throws java.io.IOException
org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation

Creo que probablemente MappingJackson2HttpMessageConverter no se está cargando durante la prueba de la mía @ExceptionHandler (sin embargo, está configurado en WebConfig.class y cuando se intenta realizar una prueba típica, no se produce ninguna excepción, todo funciona bien).

Gracias de antemano por tu ayuda.


5
2017-07-15 18:09


origen


Respuestas:


No estoy seguro de si esta es la mejor solución para esto (me gustaría saber de otra),
Pero así es como soluciono este problema exactamente al que te enfrentas:

Agregue esta línea a su createExceptionResolver():

exceptionResolver.getMessageConverters().add(
        new MappingJackson2HttpMessageConverter());

Algo como esto:

private ExceptionHandlerExceptionResolver createExceptionResolver() {
    ExceptionHandlerExceptionResolver exceptionResolver = new ExceptionHandlerExceptionResolver() {
        @Override
        protected ServletInvocableHandlerMethod getExceptionHandlerMethod(
            HandlerMethod handlerMethod, Exception exception) {
            Method method = new ExceptionHandlerMethodResolver(
                    MyAppExceptionHandler.class).resolveMethod(exception);
            return new ServletInvocableHandlerMethod(
                new MyAppExceptionHandler(), method);
        }
    };
    exceptionResolver.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
    exceptionResolver.afterPropertiesSet();
    return exceptionResolver;
}

Por alguna razón que no sé, Spring no estaba cargando mi MappingJackson2HttpMessageConverter.
Esa línea resolvió mi problema.


14
2017-09-17 03:49



La MockMvcBuilders standaloneSetup es manual por definición, lo que significa que en lugar de descubrir Spring Bean de interés como @ControllerAdvice en la configuración de Spring, le permite configurar manualmente lo que necesita para la prueba. En cambio, standaloneSetup debería permitirle también registrar manualmente los beans @ControllerAdvice. Hay un boleto para que eso suceda. Ver https://jira.spring.io/browse/SPR-12751.


3
2018-02-25 15:40