问题
I am writing a Rest service using Spring MVC. Here is the outline of the class:
@Controller
public class MyController{
@RequestMapping(..)
public void myMethod(...) throws NotAuthorizedException{...}
@ExceptionHandler(NotAuthorizedException.class)
@ResponseStatus(value=HttpStatus.UNAUTHORIZED, reason="blah")
public void handler(...){...}
}
I have written my unit tests using the design posted here. The test is basically as follows:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(....)
public class mytest{
MockHttpServletRequest requestMock;
MockHttpServletResponse responseMock;
AnnotationMethodHandlerAdapter handlerAdapter;
@Before
public void setUp() {
requestMock = new MockHttpServletRequest();
requestMock.setContentType(MediaType.APPLICATION_JSON_VALUE);
requestMock.addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
responseMock = new MockHttpServletResponse();
handlerAdapter = new AnnotationMethodHandlerAdapter();
}
@Test
public void testExceptionHandler(){
// setup ....
handlerAdapter.handle(...);
// verify
// I would like to do the following
assertThat(responseMock.getStatus(), is(HttpStatus.UNAUTHORIZED.value()));
}
}
However, the call to handle
is throwing the NotAuthorizedException
. I have read that this is by design to be able to unit test that the method throws the appropriate exception, however I would like to write an automated test that the framework is handling this exception appropriately and that the class under test has implemented the handler appropriately. Is there a way to do this?
Please be aware that I do not have access to the actual code in a place where I could post it.
Also, I am limited (for unfortunate reasons) to Spring 3.0.5 or 3.1.2.
回答1:
Consider using Spring 3.2 and its mvc-test-framework
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml")
public class WebMvcTest {
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
@Test
public void getFoo() throws Exception {
this.mockMvc.perform(
get("/testx")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
)
.andExpect(status().isUnauthorized());
}
}
Controller code
@Controller
public class MyController {
public class MyException extends RuntimeException {
};
@RequestMapping("/testx")
public void myMethod() {
throw new MyException();
}
@ExceptionHandler(MyException.class)
@ResponseStatus(value = HttpStatus.UNAUTHORIZED, reason = "blah")
public void handler() {
System.out.println("handler processed");
}
}
This "test" passes well.
Disclaimer: currently I'm a noob in Spring MVC testing, actually it's my first test.
upd: Thanks to The Drake for the correction.
回答2:
Annotate your Exception Handling controller with @ControllerAdvice
instead of @Controller
.
As Boris Treukhov noted when adding the @ExceptionHandler
annotation to a method in the controller that throws the exception will make it work but only from that specific controller.
@ControllerAdvice
will allow your exception handeling methods to be applicable for your whole application not just one specific controller.
回答3:
You could change @Test to
@Test(expected=NotAuthorizedException.class)
This would return true if the internals throw up that exception and false otherwise.
This would also make the assertThat() unnecessary. You could write a second test that catches the NotAuthorizedException then you could inspect the responseMock under that condition then.
来源:https://stackoverflow.com/questions/14605287/write-junit-test-for-exceptionhandler