我有以下简单的控制器来捕获任何意外的异常:
@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);
}
}
我正在尝试使用 Spring MVC 测试框架编写集成测试。这是我到目前为止所拥有的:
@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"));
}
}
我在 Spring MVC 基础设施中注册了 ExceptionController 和模拟 StatusController。 在测试方法中,我设置了从 StatusController 抛出异常的期望。
异常被抛出,但 ExceptionController 没有处理它。
我希望能够测试 ExceptionController 是否获取异常并返回适当的响应。
关于为什么这不起作用以及我应该如何进行这种测试有什么想法吗?
谢谢。
我刚刚遇到了同样的问题,以下方法对我有用:
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.standaloneSetup(statusController)
.setControllerAdvice(new ExceptionController())
.build();
}
此代码将添加使用异常控制建议的能力。
@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;
}
由于您使用的是独立设置测试,因此您需要手动提供异常处理程序。
mockMvc= MockMvcBuilders.standaloneSetup(adminCategoryController).setSingleView(view)
.setHandlerExceptionResolvers(getSimpleMappingExceptionResolver()).build();
几天前我也遇到了同样的问题,你可以在这里看到我自己回答的问题和解决方案Spring MVC控制器异常测试
希望我的回答对你有帮助
使用 Spring MockMVC 模拟 servletContainer,以便您可以在单元测试套件中合并任何请求过滤或异常处理测试。
您可以使用以下方法配置此设置:
给出自定义 RecordNotFound 异常...
@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);
}
}
...和 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());
}
...
}
配置定制的测试上下文:设置 @ContextConfiguration 来指定测试所需的类。将 Mockito MockMvc 设置为 servlet 容器模拟器并设置测试装置和依赖项。
@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() {
}
....
配置模拟 MVC“servlet 模拟器”:在上下文中注册处理程序 bean 并构建 mockMvc 模拟器(注意:有两种可能的配置:standaloneSetup 或 webAppContextSetup;请参阅 文档)。构建器正确地实现了构建器模式,因此您可以在调用 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");
}
....
获取异常解析器
private ExceptionHandlerExceptionResolver getExceptionResolver(
StaticApplicationContext context) {
ExceptionHandlerExceptionResolver resolver = new ExceptionHandlerExceptionResolver();
resolver.getMessageConverters().add(
new MappingJackson2HttpMessageConverter());
resolver.setApplicationContext(context);
resolver.afterPropertiesSet();
return resolver;
}
运行测试
@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());
}
....
}
希望这有帮助。
杰克。
@Before
public void setup() {
this.mockMvc = MockMvcBuilders
.standaloneSetup(YOUR_REST_CONTROLLER_INSTANCE)
.setControllerAdvice(YOUR_EXCEPTION_HANDLER_INSTANCE)
.build();
}
尝试一下;
@RunWith(value = SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = { MVCConfig.class, CoreConfig.class,
PopulaterConfiguration.class })
public class ExceptionControllerTest {
private MockMvc mockMvc;
@Mock
private StatusController statusController;
@Autowired
private WebApplicationContext wac;
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).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"));
}
}
这样更好:
((HandlerExceptionResolverComposite) wac.getBean("handlerExceptionResolver")).getExceptionResolvers().get(0)
并且不要忘记在 @Configuration 类中扫描 @ControllerAdvice beans:
@ComponentScan(basePackages = {"com.company.exception"})
...在 Spring 4.0.2.RELEASE 上测试