Craig Craig - 6 days ago 4
Java Question

Unit testing spring rest controller error handling

I have a spring rest controller as detailed below

@RestController
@RequestMapping(value = "/data")
public class DataController {

private final IDataService service;
private static final Logger LOG = Logger.getLogger(DataController.class);

/**
* The Constructor.
*
* @param service
* the service
*/
@Autowired
public DataController(final IDataService service) {
this.service = service;
}

// Country
/**
* Find all countries.
*
* @return the response entity< list< country>>
*/
@RequestMapping(value = "/country", produces = Util.APPLICATION_JSON_UTF8_STRING, method = RequestMethod.GET)
public ResponseEntity<List<Country>> findAllCountries() {
List<Country> countries = new ArrayList<>();
try {
countries = this.service.findAllCountries();
return new ResponseEntity<>(countries, null, HttpStatus.OK);
} catch (final Exception e) {
LOG.error(e.getMessage(), e);
return new ResponseEntity<>(countries, null, HttpStatus.INTERNAL_SERVER_ERROR);
}
}


I have a unit test using Mockito and Mock Mvc which tests the successful path

public class DataControllerTest implements IAbstractController {

private MockMvc mockMvc;

@Mock
private IDataService serviceMock;

@InjectMocks
private DataController dataController;

@Autowired
WebApplicationContext wac;

/**
* Sets the up.
*
* @throws Exception
* the exception
*/
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(this.dataController).build();
}

@Test
public void testFindAllCountries() throws Exception {

final Country first = new CountryBuilder().id(3L).name("USA").regionId(1L).active(true).build();
final Country second = new CountryBuilder().id(66L).name("India").regionId(2L).active(true).build();
final Country third = new CountryBuilder().id(1L).name("United Kingdom").regionId(4L).active(true).build();

when(this.serviceMock.findAllCountries()).thenReturn(Arrays.asList(first, second, third));

final ResultActions ra = this.mockMvc.perform(get("/data/country.do")).andExpect(status().isOk())
.andExpect(content().contentType(Util.APPLICATION_JSON_UTF8)).andExpect(jsonPath("$", hasSize(3)))
.andExpect(jsonPath("$[0].id", is(3))).andExpect(jsonPath("$[0].name", is("USA")))
.andExpect(jsonPath("$[0].regionId", is(1))).andExpect(jsonPath("$[0].active", is(true)))
.andExpect(jsonPath("$[1].id", is(66))).andExpect(jsonPath("$[1].name", is("India")))
.andExpect(jsonPath("$[1].regionId", is(2))).andExpect(jsonPath("$[1].active", is(true)))
.andExpect(jsonPath("$[2].id", is(1))).andExpect(jsonPath("$[2].name", is("United Kingdom")))
.andExpect(jsonPath("$[2].regionId", is(4))).andExpect(jsonPath("$[2].active", is(true)));

Assert.assertNotNull(ra);
verify(this.serviceMock, times(1)).findAllCountries();
verifyNoMoreInteractions(this.serviceMock);

}


However, I am struggling to test the catch block where an error response is returned. What are the best practices around this? Can anyone advise?

FYI the Abstract controller just contains annotations

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
public interface IAbstractController {

}


So the test I am trying is

@Test(expected = Exception.class)
public void testFindAllCountriesThrowsException() throws Exception {
Mockito.doThrow(new RuntimeException()).when(this.serviceMock.findAllCountries());
this.mockMvc.perform(get("/data/country.do"));
}


Whilst this test passes, accorrding to the coverage infor from EclEmma, my catch block is still not being covered by the test

Answer

In your test, try using

Mockito.doThrow(new RuntimeException()).when(this.serviceMock).findAllCountries());

If you encounter a compile error, you might also use

when(this.serviceMock.findAllCountries()).thenThrow(new RuntimeException());