I am new to JUnit and Mockito framework. Here I am trying to mock the rest template and wanted to return an HTTP Status of 200, but still, it returns a null value. Can someone tell me whats is wrong with my implementation and why is it returning a null value, not HttpStatus OK .
Class MyDependencies{
#Autowired
RestTemplate template;
}
Class ABC extends MyDependencies{
void verify(){
try{
ResponseEntity<Object> response;
try{
response= template.postForEntity("localhost:....",obj,obj);
}catch(Exception e){
throws Exception.......
}
if(response.getStatusCodeValue()==200) // When reaches here, Exception is thrown
// becoz response is null
return new ResponseEntity<>(HttpStatus.OK);
else
throw Custom_Exception.....
}catch(Exception e){
throws Exception.....
}
}
}
Testing
Class MyTesting{
#InjectMocks
ABC abc;
#Mock
RestTemplate template;
#BeforeEach
void setUp(){
abc=new ABC();
MockitoAnnotations.initMocks(this);
}
#Test
void testingIt(){
when(template.postForEntity(anyString(),any(),any())).thenReturn(new ResponseEntity<>(HttpStatus.OK));
Assertions.asserDoesNotThrow(()->abc.verify());
}
}
The issue is the matchers which we are supplying from test method are not matching the actual function call in the service class, hence the stub is not executed and the response is null.
Try specifying the when stub like this
when(restTemplate.postForEntity(anyString(), any(), Mockito.<Class<String>>any()))
.thenReturn(new ResponseEntity<String>("{\"status\" : \"ok\"}", HttpStatus.OK));
In this case, I have taken the String as an entity I am posting through rest template. You may use some other class here.
Service class call for this will look like this
ResponseEntity<String> answer = template.postForEntity("/abc/1", entity, String.class);
Also, you have #InjectMocks on your service class in your test, so you don't need this line
abc = new ABC();
MockitoAnnotations.initMocks(this) is already doing that for you.
#code_mechanic is right, issue is with the matchers supplied from the test method.
Rather than below in test method:
when(template.postForEntity(anyString(),any(),any())).thenReturn(new ResponseEntity<>(HttpStatus.OK));
Try this, provide url not anyString() :
when(template.postForEntity(ArgumentMatchers.endsWith("/abc/1"),any(),any())).thenReturn(new ResponseEntity<>(HttpStatus.OK));
This way it will figure out URL matching stub, it worked for me.
Related
ive tried switch to a when() and get compiler errors
i have successfully used doThrow(...) in another test in the same project, so i dont know whats going on here
Unit test code:
doThrow(new Exception("the client cancelled the request, ya dingus!")).when(handler).write(any());
MvcResult result = mockMvc.perform(post("/myPath")
.content(String.valueOf(mockValidRequest))
.contentType(MediaType.APPLICATION_JSON)
.characterEncoding("utf-8"))
.andExpect(status().is5xxServerError())
.andReturn();
Code I am testing (handler method for /myPath):
#PostMapping("/myPath")
public ResponseEntity<String> handleRequest(#RequestBody MyPojo request) {
try {
handler.write(request);
} catch (Exception e) {
return new ResponseEntity<>("Exception thrown during event processing: " + e, HttpStatus.SERVICE_UNAVAILABLE);
}
return new ResponseEntity<>("Success", HttpStatus.OK)
}
The problem is the test says the actual result is a 200 success, when there should have been an exception caught, and a service unavailable 5xx response.
So I found the proper answer to my issue:
I didnt have this snippet in my original post, but the handler was being instantiated in the test like this:
#Mock
EventHandler handler;
it needed to be:
#MockBean
EventHandler handler;
My guess is since #MockBean is the spring mock, and #Mock is from Mockito, it was probably mocking an event handler that was instantiated outside of the Spring container. Thus why I didnt think it was picking up the doThrow ... it did pick it up, but spied on the wrong instance.
i found that i could get the tests to pass calling the function directly ... it just seems like MockMvc is not incorporating the doThrow logic
revised unit test:
doThrow(new Exception("some error")).when(handler).sendToSqsWriter(any());
ResponseEntity<String> response = controller.handleRequest(new Gson().fromJson(new JSONObject(mockApptRequestBody);.toString(), SeamAppointmentRequest.class));
assertTrue(response.toString().contains("some error"));
assertTrue(response.getStatusCodeValue() == 503);
all the json/gson jazz is resolving runtime parsing errors
I have a method in which is it using RestTemplate. I using the following code to make a call:
final ResponseEntity<RESTResponse> responseEntity = restTemplate.exchange(uri,
HttpMethod.POST,
httpEntityWithHeaders,
RESTResponse.class);
httpEntityWithHeads is of type HttpEntity<String>. I am writing a test and trying to mock RestTemplate so that when it calls the exchange method, it will throw an exception.
I am trying to mock it like this:
when(restTemplate.exchange(
ArgumentMatchers.contains(randomHost),
ArgumentMatchers.eq(HttpMethod.POST),
ArgumentMatchers.<HttpEntity<List<String>>>any(),
ArgumentMatchers.<ParameterizedTypeReference<List<RESTResponse>>>any())
).thenThrow(new ResourceAccessException("Random exception message."));
But when running the test, it doesn't throw the exception, it just continues.
Any suggestions?
As you said httpEntityWithHeads is of type HttpEntity<String>, so you have to stub in way that matches to HttpEntity<String>
when(restTemplate.exchange(
ArgumentMatchers.contains(randomHost),
ArgumentMatchers.eq(HttpMethod.POST),
ArgumentMatchers.<HttpEntity<String>>any(),
ArgumentMatchers.<ParameterizedTypeReference<List<RESTResponse>>>any())
).thenThrow(new ResourceAccessException("Random exception message."));
To me seems that your last parameter is not a list it is a class, and that is why the stub is failing, I tried the following and it is working.
#Test(expected = IllegalArgumentException.class)
public void test() {
RestTemplate restTemplate = mock(RestTemplate.class);
when(restTemplate.exchange(anyString(), ArgumentMatchers.eq(HttpMethod.POST),
any(HttpEntity.class),
any(Class.class))).thenThrow(new IllegalArgumentException("a"));
Rest rest = new Rest(restTemplate);
rest.call();
}
public void call(){
HttpEntity<Object> httpEntityWithHeaders= new HttpEntity<>(null);
final ResponseEntity<Object> responseEntity = restTemplate.exchange("a",
HttpMethod.POST,
httpEntityWithHeaders,
Object.class);
}
I have an issue when trying to test a class that represents a Rest Client. I'm using RestTemplate in Spring Boot.
This is the abstract RestClient class:
public abstract class RestClient {
...
public RestResponse sendPostRequest(URI baseUri, String resource, IRestRequest restRequest, ClassresponseClass)
throws ServerException, ClientException {
...
try {
RestTemplate restTemplate = new RestTemplate();
response = restTemplate.exchange(baseUri, HttpMethod.POST, getEntity(restRequest), responseClass);
result = response.getBody();
getLogger().debug("[{}] received", result);
return result;
} catch (HttpClientErrorException e) {
throw new ClientException(e.getCause());
} catch (HttpServerErrorException e) {
throw new ServerException(e.getCause());
} catch (Exception e) {
getLogger().error("Error with cause: {}.", e.getMessage());
}
...
}
}
This is the actual implementation:
public class ActualRestClient extends RestClient {
public RestResponse sendFetchFileRequest(URI baseUri, FetchFileRequest request) throws ServerException, ClientException {
return sendPostRequest(baseUri, "FETCH_FILE", request, RestResponse.class);
}
}
An this is the test:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ActualRestClient.class, RestClient.class})
public class ActualResRestClientTest {
private static final String REQUEST_URI = "something";
#InjectMocks
public ActualRestClient testee;
#Mock
private RestTemplate restTemplate;
#Test(expected = ServerException.class)
public void sendPostRequestWithResponseBody_throwsServerException() throws Exception {
HttpServerErrorException httpServerErrorException = new HttpServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR);
when(restTemplate.exchange(Mockito.any(URI.class), eq(HttpMethod.POST), Mockito.any(), eq(FetchFileRequest.class))).thenThrow(httpServerErrorException);
testee.sendFetchFileRequest(new URI(REQUEST_URI), new FetchFileRequest());
}
}
ClientException and ServerException are exceptions created by me by extending Exception class.
My problem is that in the RestClient class another Exception is catched(message:"URI is not absolute") instead of HttpServerErrorException and I can't understand why. Thank you!
As the commenter already expressed: doing new URI("something") already throws at you. But even when you pass a "valid" URI, your code will not work, as there is a misconception on your end. You see:
RestTemplate restTemplate = new RestTemplate();
response = restTemplate.exchange(baseUri, HttpMethod.POST, getEntity(restRequest), responseClass);
That code lives within a method of your class under test. But #InjectMocks works only for fields of classes.
In other words: when your production code gets executed, a new (completely different** ResponseTemplate instance is created. And therefore your mocking spec is irrelevant, because the method isn't invoked on your mock in the first place.
Two choices:
turn that local variable into a field of your class under test (then injecting should work)
or, as you are already using PowerMock(ito), you could use that mocking framework to intercept that call to new().
I suggest you rather use option one, and avoid to use the PowerMock(ito) extension altogether!
This question has been asked before and I have tried their solution but that doesn't work for me, I am using MockMvc to unit test content type of my rest call.
I am getting this exception:
java.lang.AssertionError: Content type not set
While I'm setting it in my search method using produces attribute.
This is the method where I am initializing the mocks:
#Before
public void init() {
MockitoAnnotations.initMocks(this);
ReflectionTestUtils.setField(restController, "luceneSearchEnabled", true);
mockMvc = standaloneSetup(restController).build();
}
This is my test method:
#Test
public void pmmSearchContentTypeTest() throws Exception {
mockMvc
.perform(get("/api/v1/pmm").contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON_VALUE)
.andReturn();
}
This is my search method where I am setting content type:
#RequestMapping(value = "/api/" + REST_API_VERSION + "/" + ONE_INTERFACE, method = RequestMethod.GET, produces ={MediaType.APPLICATION_JSON_VALUE})
#ResponseBody
public String pmmSearch() { ... }
I don't know what is wrong here.
I faced the same error and found that , the mock service for this controller method returns null. change mock service method to return values for any() input and test this to get rid of this error.
when(service.method(any())).thenReturn(someElement);
someElement was null earlier causing this error case
Figured it out myself
Instead of using the mock object of retcontroller here
mockMvc = standaloneSetup(restController).build();
I had to use a real object
mockMvc = standaloneSetup(new RestController()).build();
and in order to avoid spring validation error I had to use complete path here
mockMvc
.perform(get("/api/v1/pmm/search{}").contentType(MediaType.APPLICATION_JSON))
If the response returns null, you can get that error, as it says #stuti-verma.
It happened to me right now.
The case: In my test, I was sending a json to the controller, but the object that I used to generate the mocked response didn't have the equals/hashCode implemented. So, it will never match with the received json.
#RequestBody anObject
mock.theMethod(anObject).thenReturn(theResponse)
anObject must have equals/hashCode to be able to be compared
In my case, I had to set the content type returned by the request in the ResponseEntity itself:
PaymentResponse paymentResponse = makePaymentService.makePayment(paymentRequest);
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json");
return new ResponseEntity<>(paymentResponse, HttpStatus.OK);
see java.lang.AssertionError: Content Type Not Set - Spring Controller JUnit Tests
I have a controller method for which i have to write a junit test
#RequestMapping(value = "/new", method = RequestMethod.GET)
public ModelAndView getNewView(Model model) {
EmployeeForm form = new EmployeeForm()
Client client = (Client) model.asMap().get("currentClient");
form.setClientId(client.getId());
model.addAttribute("employeeForm", form);
return new ModelAndView(CREATE_VIEW, model.asMap());
}
Junit test using spring mockMVC
#Test
public void getNewView() throws Exception {
this.mockMvc.perform(get("/new")).andExpect(status().isOk()).andExpect(model().attributeExists("employeeForm")
.andExpect(view().name("/new"));
}
I am getting NullPointerException as model.asMap().get("currentClient"); is returning null when the test is run, how do i set that value using spring mockmvc framework
As an easy work around you should use MockHttpServletRequestBuilder.flashAttr() in your test:
#Test
public void getNewView() throws Exception {
Client client = new Client(); // or use a mock
this.mockMvc.perform(get("/new").flashAttr("currentClient", client))
.andExpect(status().isOk())
.andExpect(model().attributeExists("employeeForm"))
.andExpect(view().name("/new"));
}
The response is given as string chain (I guess json format, as it is the usual rest service response), and thus you can access the response string via the resulting response in this way:
ResultActions result = mockMvc.perform(get("/new"));
MvcResult mvcResult = result.andExpect(status().isOk()).andReturn();
String jsonResponse = mvcResult.getResponse().getContentAsString();
And then you can access to the response via getResponse().getContentAsString(). If json/xml, parse it as an object again and check the results. The following code simply ensures the json contains string chain "employeeForm" (using asertJ - which I recommend)
assertThat(mvcResult.getResponse().getContentAsString()).contains("employeeForm")
Hope it helps...