Search code examples
javaunit-testingexceptionmockitomicronaut

Micronaut: Exception Handler is not invoked while executing Mockito tests


When I create a case where exception is thrown by the code by calling APIs, at that time, ExceptionHandler is invoked as expected. But when I try creating the same case through unit tests, at that time, ExceptionHandler is not invoked. My classes are as below:

Controller.java

@Post("/XXX")
public ResponseEntity<List<CategoryTopicBean>> listCategoryTopics(@Body CategoryIdsRequestBean categoryIdsRequestBean) {
    if (categoryIdsRequestBean.getCategoryIds().size() > MAX_ALLOWED_CATEGORY_SELECTION) {
        throw new CustomException(SystemConstants.ResponseCode.ERROR, SystemConstants.ResponseMessage.OVERFLOW_MAX_CATEGORIES);
    }
    ...

CustomExceptionHandler.java:

@Produces
@Singleton
@Requires(classes = {CustomException.class, ExceptionHandler.class})
public class CustomExceptionHandler implements ExceptionHandler<CustomException, HttpResponse> {

    @Override
    public HttpResponse handle(HttpRequest request, CustomException exception) {
        return HttpResponse.ok(new ResponseEntity<>(exception.responseCode, exception.getMessage()));
    }
}

XXXShould.java

@Test
public void should_list_category_topics() {
    CategoryIdsRequestBean categoryIdsBean = new CategoryIdsRequestBean();
    IdBean idBean = new IdBean();
    idBean.setId(ID_1);
    categoryIdsBean.setCategoryIds(Arrays.asList(idBean));

    ResponseEntity<List<CategoryTopicBean>> responseEntity = topicController.listCategoryTopics(categoryIdsBean);
    assertThat(SystemConstants.ResponseCode.SUCCESS).isEqualTo(responseEntity.getResponseCode());
    assertThat(1).isEqualTo(responseEntity.getData().size());

    categoryIdsBean = new CategoryIdsRequestBean();
    categoryIdsBean.setCategoryIds(Arrays.asList(idBean, idBean, idBean, idBean, idBean, idBean));
    responseEntity = topicController.listCategoryTopics(categoryIdsBean);
}

Can anyone please look into this, and help me out?


Solution

  • The problem here is, you are testing the controller by directly invoking the controller method topicController.listCategoryTopics(categoryIdsBean).

    This is not a good approach to test controller functionality. What you should do is use MicronautTest. MicronautTest will start an embedded server. Now you can use an HTTP client to hit the endpoint and retrieve the result.

    Your code needs to be changed to something around the lines as below.

    @MicronautTest
    class HelloWorldTest {
    
        @Inject
        @Client("/")
        RxHttpClient client;
    
        @Test
        public void should_list_category_topics() {
            // Test Data
            CategoryIdsRequestBean categoryIdsBean = new CategoryIdsRequestBean();
            IdBean idBean = new IdBean();
            idBean.setId(ID_1);
            categoryIdsBean.setCategoryIds(Arrays.asList(idBean));
    
            HttpRequest<String> request = HttpRequest.POST("/XXX", categoryIdsBean);
            ResponseEntity<List<CategoryTopicBean>> retrieve = client.toBlocking().retrieve(request, ResponseEntity.class);
    
            categoryIdsBean = new CategoryIdsRequestBean();
            categoryIdsBean.setCategoryIds(Arrays.asList(idBean, idBean, idBean, idBean, idBean, idBean));
            responseEntity = topicController.listCategoryTopics(categoryIdsBean);
        }
    }
    

    For the exception case scenario, as the exception handler returns ResponseEntity<String>, you would need to make a minor change in the above code.

    ResponseEntity<String> retrieve = client.toBlocking()
                                   .retrieve(request, ResponseEntity.class);
    

    If your controller calls any other service, do not forget to mock the behavior.