How to test restclient using RestTemplate and JUnit? - java

I am new to JUNIT and using RestTemplate to call my service, I'm getting 200 response for the same. But, I can't test the class using JUnit. Tried different approaches and getting 400 and 404. I want to post the request body (json) and test the status. Please let me know if there is any issue.
/**
* Rest client implementation
**/
public class CreateEmailDelegate implements CDM {
#Autowired
private RestTemplate restTemplate;
private String url = "http://example.com/communications/emails";
public ResponseEntity<CDResponse> createEmail(CDMEmailRequest cDRequest) throws UnavailableServiceException, InvalidInputException {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("SR_API_Key", SR_API_KEY);
httpHeaders.set("consumerIdentification", CONSUMER_IDENTIFICATION);
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
HttpEntity< CDMEmailRequest > cDRequestEntity = new HttpEntity<>( cDRequest, httpHeaders);
ResponseEntity< CDResponse > cDResponse = null;
try {
cDResponse = restTemplate.postForEntity(url, cDRequestEntity, CDResponse.class);
} catch (Exception e) {
LOGGER.error(e.getMessage());
throw e;
}
return cDResponse;
}
}
My Test class which return 404 status instead of 200
#RunWith(SpringJUnit4ClassRunner.class)
public class CreateEmailCommunicationDelegateTest {
#Before
public void setup() {
httpHeaders = new HttpHeaders();
httpHeaders.set("SR_API_Key", SR_API_KEY);
httpHeaders.set("consumerIdentification", CONSUMER_IDENTIFICATION);
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
DefaultMockMvcBuilder builder = MockMvcBuilders.webAppContextSetup(this.wac);
this.mockMvc = builder.build();
}
public void testResponse() throws Exception, HttpClientErrorException, JsonProcessingException {
String url = "http://example.com/CommunicationDeliveryManagement-Service-1.0.0/communications/emails";
CDMEmailRequest anObject = new CDMEmailRequest();
ResultMatcher ok = MockMvcResultMatchers.status().isOk();
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, false);
ObjectWriter ow = mapper.writer().withDefaultPrettyPrinter();
String requestJson = ow.writeValueAsString(anObject);
System.out.println(requestJson);
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.post(url).contentType(MediaType.APPLICATION_JSON_UTF8).content(requestJson);
this.mockMvc.perform(builder).andExpect(ok).andDo(MockMvcResultHandlers.print());
}
}
My Test class using TestRestTemplate instead MockMvc returns 400
#RunWith(SpringJUnit4ClassRunner.class)
public class CreateEmailCommunicationDelegateTest {
#Before
public void setup() {
httpHeaders = new HttpHeaders();
// rest headers as above
}
#Test
public void testResponse() throws Exception, HttpClientErrorException, JsonProcessingException {
String url = "http://example.com/CommunicationDeliveryManagement-Service-1.0.0/communications/emails";
String username = "";
String password = "";
HttpEntity<CDMEmailRequest>
cDEntity = new HttpEntity<>(httpHeaders);
restTemplate = new TestRestTemplate(username, password);
responseEntity =
restTemplate.exchange(url, HttpMethod.POST, cDEntity,
CDResponse.class);
assertNotNull(responseEntity);
assertEquals(HttpStatus.OK,
responseEntity.getStatusCode());
}
}

I think you're trying to implement an integration test instead of an unit test, there is quite difference. MockMvc should be used to implement unit tests and TestRestTemplate for integration tests. You can't neither use it for testing a Client implementation.
See Unit and Integration Tests in Spring Boot
If you are working with Spring Boot you could achieve your goal using another approach see this question Spring boot testing of a rest client using #RestClientTest.

Related

How to test a spring postmapping? (Junit)

Im trying to test a sample post where you have a endpoint called /message which is a path parameter on localhost. The message is a var so if I post /samplemsg as an example it should print that. However Im not quite sure how to test the post. Here's what I've managed to do so far
#RestController
#Component
#RequestMapping(path = "/message")
public class HomeController {
#PostMapping(path="/message")
public ResponseEntity<Object> postName(#PathParam ("message") #RequestBody String message) {
URI location = URI.create(ServletUriComponentsBuilder.fromCurrentRequest().buildAndExpand(message + " was created").toUriString());
return ResponseEntity.created(location).build();
}
Test Class
#RunWith(SpringRunner.class)
#SpringBootTest(classes= RunApplication.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
class RunApplicationTests {
#Autowired
private TestRestTemplate restTemplate;
#Test
void sendPost() throws URISyntaxException {
final String baseUrl = "http://localhost:8080/message";
URI uri = new URI(baseUrl);
String message = "sample msg";
HttpHeaders headers = new HttpHeaders();
headers.set("X-COM-PERSIST", "true");
HttpEntity<String> request = new HttpEntity<>(message, headers);
ResponseEntity<String> result = this.restTemplate.postForEntity(uri, request, String.class);
Assert.assertEquals("sample msg was created", result.getBody().toString());
}
}
Error Message:
org.junit.ComparisonFailure: expected:<[sample msg was created]> but was:<[{"timestamp":"2022-02-14T21:54:29.152+00:00","status":404,"error":"Not Found","path":"/message/"}]>
Expected :sample msg was created
Actual :{"timestamp":"2022-02-14T21:54:29.152+00:00","status":404,"error":"Not Found","path":"/message/"}

JUnit test for void method containing a RestTemplate exchange call

I am trying to write a Test class for one of my methods and I am new to JUnit. My class returns a void and has a RestTemplate.exchange call to an external endpoint.
I started off trying this, but this gives me a NullInsteadOfMockException.
#Test
public void service1test() throws IOException{
ResponseEntity<?> responseEntity = new ResponseEntity<>(HttpStatus.ACCEPTED);
RestTemplate restTemplate = Mockito.mock(RestTemplate.class);
Mockito.verify(restTemplate.exchange(Mockito.anyString(), Mockito.<HttpMethod> any(), Mockito.<HttpEntity<?>> any(), Mockito.<Class<?>> any(),
Mockito.<String, String> anyMap()));
}
Here's my method that I want to write unit test for.
#Autowired
private RestTemplate restTemplate;
public void service1(String a, String b) {
RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder();
this.restTemplate = restTemplateBuilder.build();
HttpHeaders headers = new HttpHeaders();
try {
headers.set("ID", ID);
headers.set("secret", secret);
System.out.println(docStoreUrl + itemID);
HttpEntity requestEntity = new HttpEntity<>(null, headers);
ResponseEntity response = restTemplate.exchange(url, HttpMethod.GET, requestEntity, Object.class);
log.info("Status code for get : {}", response.getStatusCodeValue());
if(response.getStatusCodeValue() == 200) {
Object document = (Object) response.getBody();
Class2.service2.execute(document);
}
else {
log.info("Failed to retrieve document due to {}", response.getStatusCodeValue());
}
}
I am new to JUnit testing and can't figure out how to write the Test class for this covering all the lines.
If this question is already answered, please point me to the appropriate URL.
Any help will be greatly appreciated.
Its a little bit late, but if anyone else falls over this:
This error will also occur, if you are using mockito wrong.
It should be:
Mockito.verify(restTemplate).exchange(Mockito.anyString() ...
Notice the closing bracket immediately after restTemplate, so exchange is called on top of mockito.

How to test Rest API endpoint which takes value from constantly changing external API

I use external API, which returns list of sorted by date Objects with many (approx. 30) properties.
I wrote simple Rest API using Spring Boot with one endpoint
/newest_obj_name
which just return currently newest name of Object from that list and ignore everything else.
How can I sufficiently test that code while the value from external API is constantly changing, so I cannot simply use String expected as in a code below?
Generally speaking how to approach whole testing issue in that scenario?
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MyTest {
#LocalServerPort
private int port;
private TestRestTemplate restTemplate = new TestRestTemplate();
private HttpHeaders headers = new HttpHeaders();
#Test
public void testRetrieveNewest() {
HttpEntity<String> entity = new HttpEntity<String>(null, headers);
ResponseEntity<String> response = restTemplate.exchange(
createURLWithPort("/newest_obj_name"),
HttpMethod.GET, entity, String.class);
String expected = "{\"name\":\"crazy\"}";
try {
JSONAssert.assertEquals(expected, response.getBody(), false);
} catch (JSONException e) {
e.printStackTrace();
}
}
private String createURLWithPort(String uri) {
return "http://localhost:" + port + uri;
}
}

How to test injected mock with try-catch

I'm doing simple unit test by using mockMvc with springboot. SampleCtrl.java is origin source code and SampleCtrlTest.java is test source code. There are 3 mocks injected to SampleCtrl and they are working well except SampleService class. As you can see, SampleService wrapped with try-catch block. So, I have no idea how to call the method in mock class to get return or throw exception in test source code.
I removed try-catch block in origin code, also given() method in test code. It worked well. That's why I think the try-catch block is undoubted reason to make error.
SampleCtrl.java
#PostMapping(path = "/save", consumes = "application/json")
#ResponseBody
public ResponseEntity<Map<String, Object>> setEmp(#RequestBody
List<EmpSaveVo> vos) {
result.clear();
try {
msg = service.setEmp(vos);
} catch (Exception e) {
msg = e.getMessage();
}
result = messageTrans.getMapLang(msg);
return messageReturn.getRestResp(result, msg);
}
SampleCtrlTest.java
private MockMvc mockMvc;
#Mock
private SampleService service;
#Mock
private MessageTrans messageTrans;
#Mock
private MessageReturn messageReturn;
#InjectMocks
private SampleCtrl sampleCtrl;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(sampleCtrl).build();
}
#Test
public void givenEmployeeDataWhenPostEmpSave() throws Exception {
List<EmpSaveVo> empSaveVos = new ArrayList<>();
EmpSaveVo empSaveVo = new EmpSaveVo();
empSaveVo.setEmployeeId(100L);
empSaveVo.set_status((long) Status.Modified.getStatus());
empSaveVos.add(empSaveVo);
Gson gson = new Gson();
String element = gson.toJson(empSaveVos);
String msg = "Test";
Map<String, Object> result = new HashMap<>();
result.put("message", msg);
given(service.setEmp(empSaveVos)).willThrow(new Exception());
given(messageTrans.getMapLang(msg)).willReturn(result);
given(messageReturn.getRestResp(any(), anyString()))
.willReturn(new ResponseEntity<Map<String, Object>>(result, HttpStatus.OK));
mockMvc.perform(post("/api/emp/save")
.content(element)
.contentType(MediaType.APPLICATION_JSON)).andDo(print())
.andExpect(status().isOk());
}
Consequently, I want to see this console log.
MockHttpServletResponse:
Status = 200
Error message = null
Headers = [Content-Type:"application/json;charset=UTF-8"]
Content type = application/json;charset=UTF-8
Body = {"message":"Test"}
Forwarded URL = null
Redirected URL = null
Cookies = []

How test this service using spring

I am trying to test the restTemplate.exchange but my test always skips the Try
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
String uri = resultado.getDatos().getPeticion().getUrl();
ResponseEntity<ResultadoPeticionDto> respuesta = null;
try{
respuesta = restTemplate.exchange(uri, HttpMethod.GET, entity, ResultadoPeticionDto.class);
resultado.getDatos().setFechaFin(new Date());
Calificacion calificacion = null;
resultado.getDatos().setResultado(calificacion.valueOf(respuesta.getBody().getCodigoError()));
resultado.getDatos().setMensaje(respuesta.getBody().getMensaje());
}catch (ResourceAccessException e) {
resultado.setCodigo(404);
resultado.setSuccess(false);
return resultado;
}catch (Exception e) {
resultado.setCodigo(500);
resultado.setSuccess(false);
return resultado;
}
this is my Mockito in the test:
Mockito.when(restTemplate.exchange(Mockito.anyString(),
Mockito.eq(HttpMethod.GET), Mockito.<HttpEntity<?>> any(),
Mockito.eq(ResultadoPeticionDto.class))).thenReturn(response);
peticionManager.peticion(resultado);
but it doesn't work, in the line of the request it run normally and skip my configuraction in the when, i'm using
#Mock
private RestTemplate restTemplate;
#InjectMocks
PeticionManager peticionManager;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
in the test class, any idea?
The katch captures the exception (code 500) and fails to provide coverage when attempting to be the target of my test

Categories