1

I have been going round and round in circles trying to fix a test and nothing on SO or other online sources have provided a solution. I have this @ControllerAdvice method to handle the MyException Exception which is:

@ControllerAdvice
public class MyControllerAdvice {
    @ExceptionHandler(MyException.class)
    @ResponseBody
    public HttpEntity<ErrorDetail> handleMyException(MyException exception) {
        return new ResponseEntity<>(exception.getErrorDetail(), exception.getHttpStatus();
    }
}

And I have a controller:

@Controller
@RequestMapping(value = "/image")
public class ImageController {
    @Autowired
    private MyImageService imageService;

    @RequestMapping(value = "/{IMG_ID}", method = RequestMethod.GET, 
         produces = MediaType.IMAGE_PNG_VALUE)
    public HttpEntity<?> getImage(String imageId) {
        byte[] imageBytes = imageService.findOne(imageId); // Exception thrown here
        ....
        return new ResponseEntity<>(imageBytes, HttpStatus.OK);
    }
    ...
}

Which is tested by:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MyApplication.class)
@WebAppConfiguration
@IntegrationTest("server.port:0")
public class ThumbnailControllerTest {
    @Autowired
    private ImageController testObject;
    private ImageService mockImageService = mock(ImageService.class);

    @Autowired
    protected WebApplicationContext webApplicationContext;
    private MockMvc mockMvc;

    @Before
    public void setup() {
        testObject.setImageService(mockImageService);
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    }

    @Test
    public void testImageWhichDoesntExistReturns404() {
           doThrow(new MyException("Doesn't exist", HttpStatus.NOT_FOUND))
                 .when(mockImageService).findOne(anyString());

           mockMvc.perform(get("/image/doesnt_exist"))
               .andExpect(status().isNotFound());
    }
}

I have a similar setup for other tests but these seem to pass. However for this one I get: Failed to invoke @ExceptionHandler method: public org.springframework.http.HttpEntity<mypackage.ErrorDetail> however I know it is invoked because when I step through it is called and the logs show that it has been detected (Detected @ExceptionHandler methods in MyControllerAdvice).

My thoughts are that this is because the HttpMessageConverters aren't resolved correctly and try to resolve the output by using a ModelAndView approach and not the required JSON format. I haven't been able to force this either by using the standaloneSetup for the MockMvc (configured with the ControllerAdvice and HttpMessageConverters set) or forcing it using a HttpMessageConverters bean of the required type.

I am using the spring dependencies:

org.springframework.boot:spring-boot-starter-web:jar:1.3.1.RELEASE
org.springframework.boot:spring-boot-starter:jar:1.3.1.RELEASE
org.springframework.boot:spring-boot-starter-test:jar:1.3.1.RELEASE
org.springframework.boot:spring-boot-starter-data-rest:jar:1.3.1.RELEASE

What am I doing wrong?

joelc
  • 331
  • 3
  • 9

1 Answers1

1

I've been able to track this down to produces = MediaType.IMAGE_PNG_VALUE. If you remove that, it works fine (assuming your ErrorDetail is JSON-serializable). The thing is, AbstractMessageConverterMethodProcessor sticks with the requested type. It just skips the JSON converter because it can't produce image/png. Specifying produces = {MediaType.IMAGE_PNG_VALUE, MediaType.APPLICATION_JSON_VALUE} doesn't help either: it just picks the first type and sticks with it.

I haven't been able to figure out how to make it work with produces. Any improvements or corrections are welcome.

Sergei Tachenov
  • 24,345
  • 8
  • 57
  • 73
  • Thanks that has helped a lot, I have specified the content type as a header on the response which works fine as opposed to the `produces` which has resolved the problem. – joelc Apr 12 '16 at 08:24