The controller class looks like this:
@RestController
@RequestMapping("/api/tntcalc")
public class TransitTimeCalculatorController {
@PostMapping("/calculate")
// @PreAuthorize("hasPermission(#tenantId, '/api/tntcalc/calculate')")
public ServiceResponse<List<TNTResponseDTO>> calculateMultipleDCDate(@RequestBody @Validated ServiceRequest<List<TNTRequestDTO>> request,
@RequestHeader(value = "tenantId", required = true) String tenantId){
Context context = Context.of(FlowDetailsOperation.CALCULATEDATE);
context.put(BaseKeys.CALCUTATE_TNT_DATE, paramMapper.getParamsAsServiceRequest(new HashMap<>()));
List<TNTResponseDTO> tntResponseDTO = transitCalculatorService.calculateDate(context);
return ServiceResponseBuilder.get(tntResponseDTO);
}
}
@Service
public class TransitCalculatorService
{
@Autowired
public RestTemplate restTemplate;
public TNTResponseDTO calculateforSingleDC(TNTRequestDTO tntRequestDTO, HttpHeaders headers)
{
Integer idc = tntRequestDTO.getIdcNbr();
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseUrl + "dates")
.queryParam("gs_tenant", tntRequestDTO.getPurchaseCompany())
.queryParam("po_type", tntRequestDTO.getPoType())
.queryParam("order_type", tntRequestDTO.getOrderType())
.queryParam("transport_mode", tntRequestDTO.getTransportMode())
.queryParam("origin", tntRequestDTO.getOrigin())
.queryParam("destination", tntRequestDTO.getDestination())
.queryParam("calculation_date_type", tntRequestDTO.getCalculationDateType())
.queryParam("calculation_date", tntRequestDTO.getCalculationDate());
HttpEntity<Void> requestEntity = new HttpEntity<>(headers);
try {
System.out.println("restTemple hashcode");
System.out.println(restTemplate.hashCode());
ResponseEntity<CalculateDateResponseDTO> responseEntity = restTemplate.exchange(builder.toUriString(), HttpMethod.GET, requestEntity, CalculateDateResponseDTO.class);
System.out.println("This is what I got::::");
System.out.println(responseEntity.getBody());
TNTResponseDTO responseDTO = new TNTResponseDTO();
responseDTO.setIdcNbr(tntRequestDTO.getIdcNbr());
responseDTO.setDates(responseEntity.getBody());
return responseDTO;
} catch (HttpClientErrorException ex) {
System.out.println("Inside Exception mehhh");
Pattern pattern = Pattern.compile("\"message\"\\s*:\\s*\"([^\"]+)\"");
Matcher matcher = pattern.matcher(ex.getMessage());
String errorMessage = "Invalid Input";
if (matcher.find()) {
errorMessage = matcher.group(1);
}
throw new AllocationRuntimeException(ErrorCodes.INVALID_INPUT.getError(errorMessage + " FOR IDC " + idc.toString()));
}
}
public List<TNTResponseDTO> calculateDate(Context context) {
ServiceRequest<Map<String, Object>> serviceRequest = context.get(BaseKeys.CALCUTATE_TNT_DATE);
Map<String, Object> request = serviceRequest.getPayload();
ServiceRequest<List<TNTRequestDTO>> tntRequestDTOSR = (ServiceRequest<List<TNTRequestDTO>>) request.get(ContextMapConstants.REQUEST);
List<TNTRequestDTO> tntRequestDTO = tntRequestDTOSR.getPayload();
List<TNTResponseDTO> responseDTO = new ArrayList<>();
HttpHeaders headers = tntServiceUtil.getTNTCalcHeaders();
for (TNTRequestDTO req : tntRequestDTO) {
System.out.println("Req "+req);
responseDTO.add(calculateforSingleDC(req, headers));
}
return responseDTO;
}
}
Now I am writing API testing for the Controller class and mocking the dependent RestTemplate object this way:
@Mock
private RestTemplate restTemplate;
@InjectMocks
private TransitCalculatorService transitCalculatorService;
@Test
public void calculateMultipleDCDateSuccessTest() throws Exception{
// List<TNTRequestDTO> ls = new ArrayList<>();
// TNTRequestDTO ele = new TNTRequestDTO(4892,"SAMS_US",20,2100,1,857,3020,"IN_STORE","2024-05-10","Container","Seasonal");
// ls.add(ele);
// ServiceRequest<List<TNTRequestDTO>> serviceRequest = new ServiceRequest<>();
// serviceRequest.setPayload(ls);
// String payload = gson.toJson(serviceRequest);
System.out.println("HashCode Mock "+restTemplate.hashCode());
ResponseEntity<CalculateDateResponseDTO> responseEntity = new ResponseEntity<>(new CalculateDateResponseDTO(), HttpStatus.OK);
String rsp = gson.toJson(new CalculateDateResponseDTO());
// Mockito.when(restTemplate.exchange(
// ArgumentMatchers.anyString(),
// ArgumentMatchers.eq(HttpMethod.GET),
// ArgumentMatchers.<HttpEntity<Void>>any(),
// ArgumentMatchers.<ParameterizedTypeReference<CalculateDateResponseDTO>>any())
// ).thenReturn(responseEntity);
Mockito.when
(
transitCalculatorService.restTemplate.exchange
(
anyString(),
any(),
any(),
ArgumentMatchers.<ParameterizedTypeReference<CalculateDateResponseDTO>>any()
)
).thenReturn(responseEntity);
// Mockito.when(this.restTemplate.exchange(
// anyString(),
// any(),
// any(),
// eq(String.class),
// anyString())
// )
// .thenReturn(new ResponseEntity<>(rsp, HttpStatus.OK));
RequestBuilder requestBuilder = MockMvcRequestBuilders
.post("/api/tntcalc/calculate")
.content(TransitCalculatorPayloads.getTransitCal())
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.header(ConstantsUtil.apiName, ConstantsUtil.apiValue)
.header(ConstantsUtil.tracking,ConstantsUtil.trackingValue)
.header(ConstantsUtil.tenantIdKey, ConstantsUtil.tenantIdValueUS);
MvcResult result = mockMvc.perform(requestBuilder)
.andReturn();
MockHttpServletResponse response = result.getResponse();
assertEquals(200,response.getStatus());
}
}
None of the mocking is working. I am getting this error:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.web.client.HttpServerErrorException$BadGateway: 502 Bad Gateway: "Unable to route request. Expected request headers {"wm_svc.name": "GST-TNT-CALC", "wm_svc.env": "dev"}"
Which happens if I directly call the URL without passing the headers required. I also printed the hashcode of the mock Resttemplat object and the autowired one in the service class and they are different.
So what is the issue? Is my Resttemplate object not mocked correctly? Why it's not returning the mocked value I want ?