it-swarm.com.de

Spring MVC @ExceptionHandler-Methode mit Spring MVC-Test testen

Ich habe den folgenden einfachen Controller, um unerwartete Ausnahmen abzufangen:

@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);
    }
}

Ich versuche, einen Integrationstest mit Spring MVC Test Framework zu schreiben. Das habe ich bisher:

@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"));
    }
}

Ich registriere den ExceptionController und einen Mock-StatusController in der Spring MVC-Infrastruktur .. __ In der Testmethode setze ich die Erwartung, eine Ausnahme vom StatusController auszulösen.

Die Ausnahme wird ausgelöst, aber der ExceptionController behandelt das nicht.

Ich möchte in der Lage sein zu testen, dass der ExceptionController Ausnahmen erhält und eine entsprechende Antwort zurückgibt.

Irgendwelche Gedanken, warum dies nicht funktioniert und wie ich diese Art von Tests durchführen sollte?

Vielen Dank.

34
C0deAttack

Ich hatte gerade die gleiche Ausgabe und die folgenden Arbeiten für mich:

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

Dieser Code bietet die Möglichkeit, kontrollierte Hinweise für Ausnahmen zu verwenden.

@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;
}
4

Da Sie einen eigenständigen Setup-Test verwenden, müssen Sie den Ausnahmehandler manuell bereitstellen.

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

Ich hatte vor ein paar Tagen dasselbe Problem. Sie können mein Problem und meine Lösung hier selbst beantworten. Spring MVC Controller Exception Test

Ich hoffe, meine Antwort hilft dir aus

2
Agung Setiawan

Verwenden Sie Spring MockMVC, um einen ServletContainer so zu emulieren, dass Sie beliebige Anforderungsfilterungstests oder Ausnahmebehandlungstests in Ihre Einheitstestsuite integrieren können.

Sie können dieses Setup auf folgende Weise konfigurieren:

Bei einer benutzerdefinierten RecordNotFound-Ausnahme ... 

@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);
    }
}

... und ein 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());
    }
   ...
}

Konfigurieren Sie einen angepassten Testkontext: Legen Sie eine @ContextConfiguration fest, um die Klassen anzugeben, die Sie für Ihren Test benötigen. Legen Sie Mockito MockMvc als Servlet-Container-Emulator fest und legen Sie das Testgerät und die Abhängigkeiten fest.

 @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() {
    }
   ....

Konfigurieren Sie einen Mock-MVC-"Servlet-Emulator": Registrieren Sie Handler-Beans im Kontext und erstellen Sie den MockMvc-Emulator (Hinweis: Es gibt zwei mögliche Konfigurationen: standaloneSetup oder webAppContextSetup; siehe documentation ). Der Builder implementiert das Builder-Muster zu Recht, sodass Sie Konfigurationsbefehle für Ausnahmeauflöser und Handler vor dem Aufruf von build () verketten können.

    @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");
    }
    ....

Führen Sie Ihre Tests durch

    @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());
    }
    ....
}

Hoffe das hilft.

Jake.

1
softjake

Das ist besser:

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

Vergessen Sie nicht, nach @ControllerAdvice-Beans in Ihrer @Configuration-Klasse zu suchen:

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

... getestet am Frühling 4.0.2.RELEASE

0
Adam Dec