I am creating my controller and controller advice like this:
Test class:
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestController {
private MockMvc mockMvc;
@Mock
private MyService myService;
@Autowired
@InjectMocks
private MyController myController;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
//Build the controller mock handler
mockMvc = MockMvcBuilders
.standaloneSetup(MyController.class)
.setControllerAdvice(new MyControllerAdvice())
//This also doesn't work
//.setHandlerExceptionResolvers(createExceptionResolver())
.build();
}
//This also did not work
private ExceptionHandlerExceptionResolver createExceptionResolver() {
ExceptionHandlerExceptionResolver exceptionResolver = new ExceptionHandlerExceptionResolver() {
protected ServletInvocableHandlerMethod getExceptionHandlerMethod(HandlerMethod handlerMethod, Exception exception) {
Method method = new ExceptionHandlerMethodResolver(MyControllerAdvice.class).resolveMethod(exception);
return new ServletInvocableHandlerMethod(new MyControllerAdvice(), method);
}
};
exceptionResolver.afterPropertiesSet();
return exceptionResolver;
}
/**
* Tests passing bad input to see if our exception handler is called.
*/
@Test
public void testBadRequest()
{
//Make a request object that has a bad input (e.g. bad date string)
MyRequest request = new MyRequest();
//Set the request values
request.setDate( "a" );
try
{
myController.getSomething( request );
}
catch (Exception e)
{
//It reaches here without ever reaching my controller advice in debugging
e.printStackTrace();
}
}
}
Controller advice:
@EnableWebMvc
@ControllerAdvice
@Component
public class MyControllerAdvice {
@ExceptionHandler(value = Exception.class)
public ResponseEntity<String> handleException(HttpServletRequest request, Exception exception) throws Exception
{
//This is never called (I'm using a debugger and have a breakpoint here)
return new ResponseEntity<String>(
"test",
HttpStatus.INTERNAL_SERVER_ERROR
);
}
}
There are two issues in your example:
MockMvcBuilders#standaloneSetup() receives Controller
objects as parameters, not the Class
objects. So it should be:
mockMvc = MockMvcBuilders
.standaloneSetup(new MyController())
.setControllerAdvice(new MyControllerAdvice())
.build();
You are calling myController.getSomething( request )
directly, while you should use previously built mockMvc
. Direct call is unadvised as it's not processed with TestDispatcherServlet
. Here is a couple of examples for mockMvc
requests:
GET
mockMvc.perform(get("/testSomething"))
.andExpect(status().is5xxServerError())
.andReturn();
POST
mockMvc.perform(post("/testSomething")
.contentType(MediaType.APPLICATION_JSON)
.content(json)) //it's JSON string
.andExpect(status().is5xxServerError())
.andReturn();