0

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

Craig
  • 341
  • 2
  • 9
  • 18
  • How are you struggling? Instruct your mock service to throw some Exception, and then invoke and assert on the error response. Not trying to be dismissive, I'm just unclear what the problem is. – Taylor Dec 01 '16 at 15:30
  • Sorry, wasnt being very clear, but the issue is taht whilst I can write atest that should throw an exception when the mock method is called, my coverage stats according to EclEmma are not showing the catch block as being covered by the test – Craig Dec 01 '16 at 15:43
  • Weird, try debugging to make sure the catch is invoked. – Taylor Dec 01 '16 at 15:55

2 Answers2

1

you have to get a error message in terms of error handling

MvcResult mvcResult = resultActions.andExpect(status().isForbidden()).andReturn();
String errMsg = mvcResult.getResponse().getErrorMessage();
Tomek Kozlowski
  • 604
  • 7
  • 6
0

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());
actc
  • 672
  • 1
  • 9
  • 23
  • Hi actc, so I tried ' @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 – Craig Dec 01 '16 at 15:39
  • According to your code you wouldn't use ```@Test(expected = Exception.class)``` as ```findAllCountries()``` always returns a ```ResponseEntity```. Remove the expected Exception and update your question. – actc Dec 01 '16 at 15:46
  • Test passes but the catch block is still marked as not covered by EclEmma when I run Coverage As -> JUnitTest (in eclipse) – Craig Dec 01 '16 at 15:48
  • Can you upload the Eclipse code coverages of test and tested class? – actc Dec 01 '16 at 15:49
  • Hi. Its working now thanks to your help. Although I did have to rephrase the throwing of the exception. It complained about unfinished stubbing with the sytnatx you suggested but reworking it resolved things. Many thanks! 'when(this.serviceMock.findAllCountries()).thenThrow(new RuntimeException("Exception thrown"));' – Craig Dec 01 '16 at 15:56