予期しない例外をキャッチするために、次のシンプルなコントローラーがあります。
@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が例外を取得し、適切な応答を返すことをテストできるようにしたいと思います。
これがなぜ機能しないのか、この種のテストをどのように行うべきかについての考えはありますか?
ありがとう。
私は同じ問題を抱えていましたが、次のように機能します:
@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 Controller Exception Test
私の答えがあなたを助けることを願っています
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をサーブレットコンテナエミュレータとして設定し、テストフィクスチャと依存関係を設定します。
@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「サーブレットエミュレータ」を設定します:コンテキストでハンドラーBeanを登録し、mockMvcエミュレーターをビルドします(注:2つの可能な設定があります:standaloneSetupまたはwebAppContextSetup。 ドキュメント )。 Builderは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());
}
....
}
お役に立てれば。
ジェイク。
これの方が良い:
((HandlerExceptionResolverComposite) wac.getBean("handlerExceptionResolver")).getExceptionResolvers().get(0)
また、@ Configurationクラスで@ControllerAdvice Beanをスキャンすることを忘れないでください。
@ComponentScan(basePackages = {"com.company.exception"})
... Spring 4.0.2.RELEASEでテスト済み