I am trying to write test for my controller with the code below. I want to cover the test for the code in the catch block statement but I'm not able to write one. I want to return a Server Response with failure code and message in the catch block.
#PostMapping(COUNTERS)
public ResponseEntity<?> getCounters(#Valid #RequestBody ApartmentCounterListRequest requestData) {
try {
log.debug("Entering API for counter list");
ApartmentCounterListResponse apartmentCounterListResponse = counterService.getAllCounters();
return ResponseEntity.ok(apartmentCounterListResponse);
} catch (Exception exception) {
log.error("Exception in counter list :: ", exception);
ServerResponse serverResponse = ResponseBuilder.buildVendorFailureMessage(new ServerResponse(),
RequestResponseCode.EXCEPTION);
return ResponseEntity.ok(JsonResponseBuilder.enquiryResponse(serverResponse));
}
}
My test code is as follows:
#Test
#DisplayName("Should return ServerResponse with failure data.")
void Should_Return_Server_Response_On_Exception() throws Exception {
/*given*/
ApartmentCounterListRequest apartmentCounterListRequest = ApartmentTestUtil.getApartmentCounterListRequest.
apply("test", "test");
Mockito.when(counterServic.getAllCounters()).thenThrow(new Exception());
// ServerResponse serverResponse = ApartmentTestUtil.getServerExceptionServerResponse.get();
/*then*/
mockMvc.perform(
post(COUNTER_URL)
.contentType(APPLICATION_JSON)
.content(objectMapper.writeValueAsString(apartmentCounterListRequest)))
.andExpect(status().isOk())
.andExpect(MockMvcResultMatchers.jsonPath("$.resultCode", Matchers.is("-6")));
verify(counterService, times(1)).getAllCounters();
}
When I run this test I am getting the following error:
org.mockito.exceptions.base.MockitoException:
Checked exception is invalid for this method!
Invalid: java.lang.Exception
I have gone through some of the following posts but haven't found a suitable answer yet.
Unit testing code in catch block of a Spring Controller
Java - How to Test Catch Block?
Unit testing code in catch block of a Spring Controller
JUnit for both try and catch block coverage
Can anyone help me write test that covers the catch block or tell me the way to do it?
I have this try catch in my controller to handle any unexpected exceptions. And for different api's I have to send a response with different response code and messages which doesnot allow me to use Exception handler.
The method you are mocking does not declare a checked exception, therefore Mockito is not able to throw one from there. Try to have the mock throw an unchecked exception (i.e. RuntimeException).
You can try to use willAnswer
Mockito.when(counterServic.getAllCounters()).thenAnswer(x -> {throw new Exception() });
Maybe this is a bit misused as Answer is used for more complex for when return
Related
I have a method which has the following code in it, it saves a order object to the orderStatus jpa repository and i have a try catch method which should capture the JDBC Connection exception.
How do i test this scenario using Junit and mockito?
try {
orderStatusRepository.save(newOrderStatus);
} catch (JDBCConnectionException ex) {
);
If the code is the goal is to test that in case JDBCConnectionException is thrown it is caught and not propagated I would suggest to mock orderStatusRepository using Mockito:
when(orderStatusRepository.save(newOrderStatus))
.thenThrow(JDBCConnectionException.class);
then execute the test and check that the method returns normally and that mocked object method was accessed (the exception therefor was thrown):
verify(orderStatusRepository).save(newOrderStatus);
Note that if save method doesn't return anything you would need to mock it a bit differently:
doThrow(JDBCConnectionException.class)
.when(orderStatusRepository).save(newOrderStatus);
follow the below code to test your code for the JDBC connection exception.
#MockBean
private OrderStatusRepository orderStatusRepository;
#Test
public void jdbcConnectionExceptionTest() {
try{
when(orderStatusRepository.save(newOrderStatus))
.thenThrow(JDBCConnectionException.class);
orderStatusRepository.save(newOrderStatus);
} catch (Exception e) {
assertTrue(e instanceof JDBCConnectionException);
}
}
try {
response = restTemplate.postForEntity(endPoint, request, Object.class);
lOGGER.info("response is " + response);
} catch (Exception e) {
lOGGER.error("Exception :" + e.getMessage());
if ((e.getMessage().contains("401") || e.getMessage().contains("Unauthorized")) ) {
ServiceImpl.evictTokenCache("authToken");
getData(requestDto);
} else {
throw new CustomException(e.getMessage());
}
above is my service and trying to write test case for catch clause,and my test case is
#Test()
public void getExceptionTest() throws Exception {
RequestDto requestDto = new RequestDto();
requestDto.setPage("1");
AuthConfig authDTO = new AuthConfig();
authDTO.setUrl("Url");
Mockito.when(restTemplate.postForEntity(Mockito.anyString(), Mockito.any(), Mockito.any())).thenThrow((new Exception("Unauthorized")));
ResponseDTO response = restCallUtil.getData(requestDto);
assertNull(response);
}
what i am trying to do incatch block is,when ever i get Unauthorized exception i am clearing the cache and calling the same method again. So in order to test catch block from my test class i am trying to throw exception with message as "Unauthorized ",but when i run test case i am getting
org.mockito.exceptions.base.MockitoException:
Checked exception is invalid for this method!
Invalid: java.lang.Exception: Unauthorized
The first thing to note is that an instance of Exception which is not also an instance of RuntimeException is a checked exception. Thus, the only way the for a method to throw a generic Exception is for the method signature to contain "throws Exception" or "throws Throwable".
So.. why are you getting this error? You are stubbing the postForEntity method which throws RestClientException, and Exception is not an instance of RestClientException. Thus, your stubbing is invalid.
If you want to stub the method such that the catch block for the generic case is entered, you will need to throw a RuntimeException, which is unchecked, and therefore not subject to the "throws" restriction.
That said, it would be probably be wiser to simply catch only the RestClientException in the original method. If there is some RuntimeException you want to catch, then you would hopefully already be aware of what that is and catch it specifically.
While testing a RestClient-Implementation I want to simulate a RestClientException that may be thrown by some RestTemplate-methods in that implementation f.e. the delete-method:
#Override
public ResponseEntity<MyResponseModel> documentDelete(String id) {
template.setErrorHandler(new MyResponseErrorHandler());
ResponseEntity<MyResponseModel> response = null;
try {
String url = baseUrl + "/document/id/{id}";
response = template.exchange(url, DELETE, null, MyResponseModel.class, id);
} catch (RestClientException ex) {
return handleException(ex);
}
return response;
}
How can I achieve this?
I define the mock-server in this way:
#Before
public void setUp() {
mockServer = MockRestServiceServer.createServer(template);
client = new MyRestClient(template, serverUrl + ":" + serverPort);
}
You can test throwing runtime exceptions from the MockRestServiceServer, although this class, as of Spring 5.0.0.RC4, is not designed for it (which means it may not work for more complex use cases):
RestTemplate yourApi;
MockRestServiceServer server = MockRestServiceServer.createServer(yourApi);
server.expect(requestTo("http://..."))
.andRespond((response) -> { throw new ResourceAccessException(
new ConnectException("Connection reset")); });
It seems to work in tests:
where there's only one RestTemplate call,
where the exception is thrown as a result of the last expectation.
I wasn't able to expect two consecutive exceptions; the MockRestSeriviceServer (more concrete, the SimpleRequestExpectationManager) throws IllegalStateException on replaying the second expectation.
You can take advantage of the MockRestResponseCreators for mocking 4xx or 5xx responses from the mockRestServiceServer.
For example for testing a 5xx - Internal server error:
mockServer.expect(requestTo("your.url"))
.andExpect(method(HttpMethod.GET/POST....))
.andRespond(withServerError()...);
In your case the RestClientException is thrown for client-side HTTP errors, so
the example above can be fine tuned for a 4xx exception by using:
...andRespond(withBadRequest()); or ...andRespond(withStatus(HttpStatus.NOT_FOUND));
For a more simpler usage of these methods you use static imports for org.springframework.test.web.client.MockRestServiceServer,org.springframework.test.web.client.response.MockRestResponseCreators
Answer by Alex Ciocan works for different http status responses, so if you want those, go with that as that's the cleanest way to go. I had a problem that I needed to be able to test also for connection reset and other network-level problems, which are trickier to simulate.
Answer by MaDa works for some use cases, but it didn't work for me when using AsyncRestTemplate, as it throws too early. However it did lead me to right direction. This one seems to work with async calls as well:
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
// ...
ClientHttpResponse exceptionThrowingResponse = mock(ClientHttpResponse.class);
when(exceptionThrowingResponse.getStatusCode()) // getRawStatusCode() in latest spring
.thenThrow(new IOException("connection reset"));
mockServer.expect(requestTo("http://localhost:123/callme"))
.andRespond((response) -> exceptionThrowingResponse);
This seems to also work for consecutive exceptions, as well as different http statuses.
How about this :
#Spy
#InjectMocks
ClasstoMock objToMock;
#Test
public void testRestClientException() throws Exception {
try {
Mockito.when(this.objToMock.perform()).thenThrow(new RestClientException("Rest Client Exception"));
this.objToMock.perform();
}
catch(Exception e){
Assert.assertEquals(RestClientException.class, e.getClass());
}
I have this code where I'm catching some exception and throwing a custom exception instead.
#Override
public void config() throws CustomException{
File jsonFile = new File("config.json");
try {
ConfigMapper config = mapper.readValue(jsonFile, ConfigMapper.class);
try {
this.instanceId = Integer.parseInt(config.getConfig().getClientId());
this.configParams = config.getConfig().getConfigParams();
} catch (NumberFormatException ex) {
throw new CustomException("Please provide a valid integer for instance ID", ex);
//LOGGER.log(Level.SEVERE, "error initializing instanceId. Should be an integer " + e);
}
} catch (IOException ex) {
throw new CustomException("Error trying to read/write", ex);
// LOGGER.log(Level.SEVERE, "IOException while processing the received init config params", e);
}
}
I need to write a unit test for this and below is how I wrote it.
#Test
public void should_throw_exception_when_invalid_integer_is_given_for_instanceID(){
boolean isExceptionThrown = false;
try{
Mockito.doThrow(new NumberFormatException()).when(objectMock).config();
barcodeScannerServiceMock.config();
} catch (CustomException ex) {
isExceptionThrown = true;
}
assertTrue(isExceptionThrown);
}
But its throwing a number format exception and not the CustomException as I want it to be. But this makes sense as I'm using the mock object to throw the exception as a result of which my code logic is not executed. But if that's the case, how do I test this scenario? Please advice.
1.) Remove the line Mockito.doThrow(new NumberFormatException()).when(objectMock).config();
2.) Change the Client-ID in your JSON-File to something that cannot be converted to an Integer.
this.instanceId = Integer.parseInt(config.getConfig().getClientId()); will fail due to that and thus throw an exception.
One advice regarding names: The name of your test method should be what's written in the Java-Doc. Just name it "testCustomException" & explain the methods function in the Java-Documentation. There are Naming-Conventions in Java (click here) which are basically general guidelines.
Practicing these is very helpful as it allows you to quickly get into your code again after not working on it for a month or so due to the increased readability.
So, I need to write a test for some (legacy) code I'm improving. In a method, I try to parse some string (which should be legal JSON). Then a possible JSONException is caught if the string doesn't represents valid JSON. Something like:
public void transformToJSON(String source) {
try {
JSONObject js = new JSONObject(new JSONTokener(item.getHtml()));
}
catch (JSONException e) {
log(e)
}
//than js is added to an Hashset and the method is done
}
So I want to write a test for good input (to see if I have generated a correct JSON-object). This is 'easy' by checking the object in the Set.
For wrong input however, I need to find out if the correct error has been thrown.
I know if an error was thrown in the code, I can check for it in the test.
By setting the rule public ExpectedException thrown=
ExpectedException.none(); and checking for it in test method.
By adding #Test(expected = JSONException.class) above the test
But both wont work for try..catch blocks.
How can I test if the proper exception is caught by catch block? I want to change as little of the source code as possible.
In the JUnit test class you can do is use fail("this should not have happened") in the try or catch block depending on what should and should not work (as in: try and catch in the JUnit class, not in your actual method!).
However, with a try/catch block within your method you cannot see whether an Exception occured or not, because it is handled within the method. So you would have to throw the exception in the method instead of catching it, i.e.,
public void transformToJSON(String source) throws JSONException { ... }
Then it will work to check whether an exception occured or not.
Alternatively you could return a boolean that states whether the transformation was successful or not. Then you can test whether the return value was true/false and if that was what you expected.
public boolean transformToJSON(String source) {
boolean success = true;
try {
JSONObject js = new JSONObject(new JSONTokener(item.getHtml()));
}
catch (JSONException e) {
log(e)
success = false;
}
//than js is added to an Hashset and the method is done
return success;
}
In your test class:
#Test
public void testTransformToJSON() {
assertTrue(transformToJSON("whatever"));
}
Based on the logging being used in the code, you can use Mockito to verify the message logged inside catch block.
Please go through the following link for more details on setting up the unit tests
http://bloodredsun.com/2010/12/09/checking-logging-in-unit-tests/
Your legacy code is swallowing the Exception. If it throws an exception, then your junit #Test ( expected = JSONException.class) would work.
I'd change the code slightly so it is
public void transformToJSON(String source) {
try {
JSONObject js = getJSON(item.getHtml()));
}
catch (JSONException e) {
log(e)
}
//than js is added to an Hashset and the method is done
}
public JSONObject getJSON(String source) throws JSONException {
return new JSONObject(new JSONTokener(source));
}
and then test against getJSON. This throws an exception and as other have said (and you) you can use the expectedException in the test class
use a bad formatted json string, and then do assertions or whatever in the catch block of ur test.
#Test
public void shouldCatchException(){
String source = "{ \"name\":\"John\", \"age\":30, \"car\":null ";
try {
jsonHelper.transformToJSON(source);
}catch (JSONException e){
Assert.assertThat(e, notNullValue());
assertTrue(StringUtils.isNotBlank(e.getMessage());
//whatever else u need to assert
}
}