Skip to content

Commit

Permalink
Regression tests for @RestControllerAdvice support in MockMvc
Browse files Browse the repository at this point in the history
This commit introduces regression tests for @RestControllerAdvice
support in standalone MockMvc configurations.

See spring-projectsgh-25520
  • Loading branch information
sbrannen authored and zx20110729 committed Feb 18, 2022
1 parent acebecc commit 3260025
Showing 1 changed file with 124 additions and 6 deletions.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -18,11 +18,16 @@

import org.junit.Test;

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
Expand All @@ -32,33 +37,81 @@
* Exception handling via {@code @ExceptionHandler} method.
*
* @author Rossen Stoyanchev
* @author Sam Brannen
*/
public class ExceptionHandlerTests {

@Test
public void testExceptionHandlerMethod() throws Exception {
public void mvcLocalExceptionHandlerMethod() throws Exception {
standaloneSetup(new PersonController()).build()
.perform(get("/person/Clyde"))
.perform(get("/person/Clyde"))
.andExpect(status().isOk())
.andExpect(forwardedUrl("errorView"));
}

@Test
public void testGlobalExceptionHandlerMethod() throws Exception {
public void mvcGlobalExceptionHandlerMethod() throws Exception {
standaloneSetup(new PersonController()).setControllerAdvice(new GlobalExceptionHandler()).build()
.perform(get("/person/Bonnie"))
.andExpect(status().isOk())
.andExpect(forwardedUrl("globalErrorView"));
}

@Test
public void testGlobalExceptionHandlerMethodUsingClassArgument() throws Exception {
public void mvcGlobalExceptionHandlerMethodUsingClassArgument() throws Exception {
standaloneSetup(PersonController.class).setControllerAdvice(GlobalExceptionHandler.class).build()
.perform(get("/person/Bonnie"))
.andExpect(status().isOk())
.andExpect(forwardedUrl("globalErrorView"));
}

@Test
public void restNoException() throws Exception {
standaloneSetup(RestPersonController.class)
.setControllerAdvice(RestGlobalExceptionHandler.class, RestPersonControllerExceptionHandler.class).build()
.perform(get("/person/Yoda").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("Yoda"));
}

@Test
public void restLocalExceptionHandlerMethod() throws Exception {
standaloneSetup(RestPersonController.class)
.setControllerAdvice(RestGlobalExceptionHandler.class, RestPersonControllerExceptionHandler.class).build()
.perform(get("/person/Luke").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.error").value("local - IllegalArgumentException"));
}

@Test
public void restGlobalExceptionHandlerMethod() throws Exception {
standaloneSetup(RestPersonController.class)
.setControllerAdvice(RestGlobalExceptionHandler.class).build()
.perform(get("/person/Leia").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.error").value("global - IllegalStateException"));
}

@Test
public void restGlobalRestPersonControllerExceptionHandlerTakesPrecedenceOverGlobalExceptionHandler() throws Exception {
standaloneSetup(RestPersonController.class)
.setControllerAdvice(RestGlobalExceptionHandler.class, RestPersonControllerExceptionHandler.class).build()
.perform(get("/person/Leia").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.error").value("globalPersonController - IllegalStateException"));
}

@Test // gh-25520
public void restNoHandlerFound() throws Exception {
standaloneSetup(RestPersonController.class)
.setControllerAdvice(RestGlobalExceptionHandler.class, RestPersonControllerExceptionHandler.class)
.addDispatcherServletCustomizer(dispatcherServlet -> dispatcherServlet.setThrowExceptionIfNoHandlerFound(true))
.build()
.perform(get("/bogus").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.error").value("global - NoHandlerFoundException"));
}


@Controller
private static class PersonController {
Expand All @@ -80,15 +133,80 @@ public String handleException(IllegalArgumentException exception) {
}
}


@ControllerAdvice
private static class GlobalExceptionHandler {

@ExceptionHandler
public String handleException(IllegalStateException exception) {
return "globalErrorView";
}
}

@RestController
private static class RestPersonController {

@GetMapping("/person/{name}")
Person get(@PathVariable String name) {
switch (name) {
case "Luke":
throw new IllegalArgumentException();
case "Leia":
throw new IllegalStateException();
default:
return new Person("Yoda");
}
}

@ExceptionHandler
Error handleException(IllegalArgumentException exception) {
return new Error("local - " + exception.getClass().getSimpleName());
}
}

@RestControllerAdvice(assignableTypes = RestPersonController.class)
@Order(Ordered.HIGHEST_PRECEDENCE)
private static class RestPersonControllerExceptionHandler {

@ExceptionHandler
Error handleException(Throwable exception) {
return new Error("globalPersonController - " + exception.getClass().getSimpleName());
}
}

@RestControllerAdvice
@Order(Ordered.LOWEST_PRECEDENCE)
private static class RestGlobalExceptionHandler {

@ExceptionHandler
Error handleException(Throwable exception) {
return new Error( "global - " + exception.getClass().getSimpleName());
}
}

static class Person {

private final String name;

Person(String name) {
this.name = name;
}

public String getName() {
return name;
}
}

static class Error {

private final String error;

Error(String error) {
this.error = error;
}

public String getError() {
return error;
}
}

}

0 comments on commit 3260025

Please sign in to comment.