J'ai le contrôleur simple suivant pour attraper toute exception inattendue:
@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);
}
}
J'essaie d'écrire un test d'intégration à l'aide de la structure de test Spring MVC. C'est ce que j'ai jusqu'ici:
@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"));
}
}
J'inscris ExceptionController et un StatusController fictif dans l'infrastructure Spring MVC . Dans la méthode de test, j'ai configuré une attente de levée d'une exception à partir de StatusController.
L'exception est levée, mais ExceptionController ne s'en occupe pas.
Je veux pouvoir vérifier que ExceptionController obtient des exceptions et renvoie une réponse appropriée.
Avez-vous des idées sur les raisons pour lesquelles cela ne fonctionne pas et sur la manière dont je devrais effectuer ce type de test?
Merci.
Je viens d'avoir le même problème et les travaux suivants pour moi:
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.standaloneSetup(statusController)
.setControllerAdvice(new ExceptionController())
.build();
}
Ce code ajoutera la possibilité d'utiliser vos avis contrôlés des exceptions.
@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;
}
Puisque vous utilisez le test de configuration autonome, vous devez fournir manuellement le gestionnaire d'exceptions.
mockMvc= MockMvcBuilders.standaloneSetup(adminCategoryController).setSingleView(view)
.setHandlerExceptionResolvers(getSimpleMappingExceptionResolver()).build();
J'ai eu le même problème quelques jours en arrière, vous pouvez voir mon problème et ma solution résolus par moi-même ici Spring MVC Controller Exception Test
En espérant que ma réponse vous aide
Utilisez Spring MockMVC pour émuler un servletContainer à un point où vous pouvez incorporer tous les tests de filtrage des demandes ou de gestion des exceptions dans votre suite de tests unitaires.
Vous pouvez configurer cette configuration avec l’approche suivante:
Étant donné une exception RecordNotFound personnalisée ...
@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);
}
}
... et 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());
}
...
}
Configurer un contexte de test personnalisé: définissez une @ContextConfiguration pour spécifier les classes dont vous avez besoin pour votre test. Définissez Mockito MockMvc en tant qu'émulateur de conteneur de servlet et définissez votre équipement de test et vos dépendances.
@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() {
}
....
Configurez un mock MVC "émulateur de servlet": inscrivez les beans gestionnaires dans le contexte et générez l'émulateur mockMvc (Remarque: il existe deux configurations possibles: standaloneSetup ou webAppContextSetup; reportez-vous à la documentation ). Le générateur implémente à juste titre le modèle Builder afin que vous puissiez chaîner les commandes de configuration pour les résolveurs d'exceptions et les gestionnaires avant d'appeler 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");
}
....
Exécuter vos tests
@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());
}
....
}
J'espère que cela t'aides.
Jake.
C'est mieux:
((HandlerExceptionResolverComposite) wac.getBean("handlerExceptionResolver")).getExceptionResolvers().get(0)
Et n'oubliez pas de rechercher les beans @ControllerAdvice dans votre classe @Configuration:
@ComponentScan(basePackages = {"com.company.exception"})
... testé sur Spring 4.0.2.LELEASE