用 Spring MVC 测试测试 Spring MVC@ExceptionHandler 方法

我有以下简单的控制器来捕捉任何意外的异常:

@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 Test 框架编写一个集成测试:

@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 获得异常并返回适当的响应。

有什么想法吗,为什么这个不起作用,我应该如何做这种测试?

谢谢。

84914 次浏览

由于您使用的是独立安装测试,因此需要手动提供异常处理程序。

mockMvc= MockMvcBuilders.standaloneSetup(adminCategoryController).setSingleView(view)
.setHandlerExceptionResolvers(getSimpleMappingExceptionResolver()).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"));
}
}

此代码将添加使用异常控制通知的能力。

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

我只是有同样的问题和以下工作为我:

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

这样更好:

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

并且不要忘记在@Configuration 类中扫描@ControllerAdvisory bean:

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

... 在 Spring 4.0上测试。2. 发布

使用 Spring MockMVC 来模拟 servletContainer,以便在单元测试套件中合并任何请求过滤或异常处理测试。

您可以使用以下方法配置此设置:

给定一个自定义 RecordNotFind 异常..。

@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 并构建模拟 MVC 模拟器(注意: 有两种可能的配置: stanaloneSetup 或 webAppContextSetup; 参考 文件)。构建器正确地实现了 Builder 模式,因此您可以在调用 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());
}
....
}

希望这个能帮上忙。

杰克。