test spring spring-mvc mockito spring-mvc-test

spring boot test



Prueba del método Spring MVC @ExceptionHandler con Spring MVC Test (6)

Acabo de tener el mismo problema y el siguiente funciona para mí:

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

Tengo el siguiente controlador simple para detectar cualquier excepción inesperada:

@ControllerAdvice public class ExceptionController { @ExceptionHandler(Throwable.class) @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR) @ResponseBody public ResponseEntity handleException(Throwable ex) { return ResponseEntityFactory.internalServerErrorResponse("Unexpected error has occurred.", ex); } }

Intento escribir una prueba de integración usando Spring MVC Test framework. Esto es lo que tengo hasta ahora:

@RunWith(MockitoJUnitRunner.class) public class ExceptionControllerTest { private MockMvc mockMvc; @Mock private StatusController statusController; @Before public void setup() { this.mockMvc = MockMvcBuilders.standaloneSetup(new ExceptionController(), statusController).build(); } @Test public void checkUnexpectedExceptionsAreCaughtAndStatusCode500IsReturnedInResponse() throws Exception { when(statusController.checkHealth()).thenThrow(new RuntimeException("Unexpected Exception")); mockMvc.perform(get("/api/status")) .andDo(print()) .andExpect(status().isInternalServerError()) .andExpect(jsonPath("$.error").value("Unexpected Exception")); } }

Registré el ExceptionController y un StatusController simulado en la infraestructura Spring MVC. En el método de prueba configuro la expectativa de lanzar una excepción desde el StatusController.

Se está lanzando la excepción, pero el ExceptionController no está tratando con eso.

Quiero poder probar que el ExceptionController recibe excepciones y devuelve una respuesta adecuada.

¿Alguna idea de por qué esto no funciona y cómo debería hacer este tipo de prueba?

Gracias.


Dado que está utilizando la prueba de configuración independiente, debe proporcionar el controlador de excepciones manualmente.

mockMvc= MockMvcBuilders.standaloneSetup(adminCategoryController).setSingleView(view) .setHandlerExceptionResolvers(getSimpleMappingExceptionResolver()).build();

Tuve el mismo problema hace unos días, puedes ver mi problema y la solución fue respondida por mí aquí Spring MVC Controller Exception Test

Espero que mi respuesta te ayude


Esta es mejor:

((HandlerExceptionResolverComposite) wac.getBean("handlerExceptionResolver")).getExceptionResolvers().get(0)

Y no olvide buscar frijoles @ControllerAdvice en su clase @Configuration:

@ComponentScan(basePackages = {"com.company.exception"})

... probado en Spring 4.0.2.RELEASE


Este código agregará la capacidad de usar sus consejos controlados por excepciones.

@Before public void setup() { this.mockMvc = standaloneSetup(commandsController) .setHandlerExceptionResolvers(withExceptionControllerAdvice()) .setMessageConverters(new MappingJackson2HttpMessageConverter()).build(); } private ExceptionHandlerExceptionResolver withExceptionControllerAdvice() { final ExceptionHandlerExceptionResolver exceptionResolver = new ExceptionHandlerExceptionResolver() { @Override protected ServletInvocableHandlerMethod getExceptionHandlerMethod(final HandlerMethod handlerMethod, final Exception exception) { Method method = new ExceptionHandlerMethodResolver(ExceptionController.class).resolveMethod(exception); if (method != null) { return new ServletInvocableHandlerMethod(new ExceptionController(), method); } return super.getExceptionHandlerMethod(handlerMethod, exception); } }; exceptionResolver.afterPropertiesSet(); return exceptionResolver; }


Intentalo;

@RunWith(value = SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration(classes = { MVCConfig.class, CoreConfig.class, PopulaterConfiguration.class }) public class ExceptionControllerTest { private MockMvc mockMvc; @Mock private StatusController statusController; @Autowired private WebApplicationContext wac; @Before public void setup() { this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); } @Test public void checkUnexpectedExceptionsAreCaughtAndStatusCode500IsReturnedInResponse() throws Exception { when(statusController.checkHealth()).thenThrow(new RuntimeException("Unexpected Exception")); mockMvc.perform(get("/api/status")) .andDo(print()) .andExpect(status().isInternalServerError()) .andExpect(jsonPath("$.error").value("Unexpected Exception")); } }


Utilice Spring MockMVC para emular un servletContainer hasta un punto donde pueda incorporar cualquier filtrado de solicitudes o pruebas de manejo de excepciones en su conjunto de pruebas unitarias.

Puede configurar esta configuración con el siguiente enfoque:

Dada una excepción personalizada RecordNotFound ...

@ResponseStatus(value=HttpStatus.NOT_FOUND, reason="Record not found") // public class RecordNotFoundException extends RuntimeException { private static final long serialVersionUID = 8857378116992711720L; public RecordNotFoundException() { super(); } public RecordNotFoundException(String message) { super(message); } }

... y un RecordNotFoundExceptionHandler

@Slf4j @ControllerAdvice public class BusinessExceptionHandler { @ExceptionHandler(value = RecordNotFoundException.class) public ResponseEntity<String> handleRecordNotFoundException( RecordNotFoundException e, WebRequest request) { //Logs LogError logging = new LogError("RecordNotFoundException", HttpStatus.NOT_FOUND, request.getDescription(true)); log.info(logging.toJson()); //Http error message HttpErrorResponse response = new HttpErrorResponse(logging.getStatus(), e.getMessage()); return new ResponseEntity<>(response.toJson(), HeaderFactory.getErrorHeaders(), response.getStatus()); } ... }

Configure un contexto de prueba personalizado : establezca una @ContextConfiguration para especificar las clases que necesita para su prueba. Configure Mockito MockMvc como un emulador de contenedor de servlets y configure el accesorio y las dependencias de las pruebas.

@RunWith(SpringRunner.class) @ContextConfiguration(classes = { WebConfig.class, HeaderFactory.class, }) @Slf4j public class OrganisationCtrlTest { private MockMvc mvc; private Organisation coorg; @MockBean private OrganisationSvc service; @InjectMocks private OrganisationCtrl controller = new OrganisationCtrl(); //Constructor public OrganisationCtrlTest() { } ....

Configure un "simulador de servlet" simulado de MVC : registre los beans controladores en el contexto y cree el emulador mockMvc (Nota: hay dos configuraciones posibles: standaloneSetup o webAppContextSetup; consulte la documentation ). El constructor implementa correctamente el patrón del generador para que pueda encadenar los comandos de configuración para los resolvers y manejadores de excepciones antes de llamar a build ().

@Before public void setUp() { final StaticApplicationContext appContext = new StaticApplicationContext(); appContext.registerBeanDefinition("BusinessExceptionHandler", new RootBeanDefinition(BusinessExceptionHandler.class, null, null)); //InternalExceptionHandler extends ResponseEntityExceptionHandler to //handle Spring internally throwned exception appContext.registerBeanDefinition("InternalExceptionHandler", new RootBeanDefinition(InternalExceptionHandler.class, null, null)); MockitoAnnotations.initMocks(this); mvc = MockMvcBuilders.standaloneSetup(controller) .setHandlerExceptionResolvers(getExceptionResolver(appContext)) .build(); coorg = OrganisationFixture.getFixture("orgID", "name", "webSiteUrl"); } ....

Ejecuta tus pruebas

@Test public void testGetSingleOrganisationRecordAnd404() throws Exception { System.out.println("testGetSingleOrganisationRecordAndSuccess"); String request = "/orgs/{id}"; log.info("Request URL: " + request); when(service.getOrganisation(anyString())). thenReturn(coorg); this.mvc.perform(get(request) .accept("application/json") .andExpect(content().contentType( .APPLICATION_JSON)) .andExpect(status().notFound()) .andDo(print()); } .... }

Espero que esto ayude.

Jake.