java spring boot, how to write a test to check send request - java

Can someone please, tell me how you can write a test. I now have to test sending a request from one server to another using RestTemplate.
class ServiceTest {
#Mock
private RestTemplate restTemplate = new RestTemplate();
#InjectMocks
private RConsumerService refundConsumerService = new RConsumerService(new RestTemplateBuilder());
#Test
public void sendRequestToBillingService(){
ChargeResponse chargeResponse = new ChargeResponse();
chargeResponse.setInstanceKey("testInstanceKey");
KafkaMessage kafkaMessage = new KafkaMessage();
kafkaMessage.setApplication_id(1L);
kafkaMessage.setCompany_id(1111);
TransactionRequestContext reqContext = refundConsumerService.createTxnRequestContext(kafkaMessage);
Mockito.when(restTemplate.postForEntity(Mockito.any()
, refundConsumerService.buildChargeRequest(reqContext), ChargeResponse.class))
.thenReturn(new ResponseEntity<>(chargeResponse, HttpStatus.OK));
refundConsumerService.refund(kafkaMessage);
assertEquals(chargeResponse.getInstanceKey(), "testInstanceKey");
}
}
How do I write the condition correctly in
Mockito.when(restTemplate.postForEntity(Mockito.any()
, refundConsumerService.buildChargeRequest(reqContext), ChargeResponse.class))
.thenReturn(new ResponseEntity<>(chargeResponse, HttpStatus.OK));
Now I am getting this exception java.lang.IllegalArgumentException: URI is required

As you are using #Mock and #InjectMocks, you don't need to create new instance of those objects. Mockito will inject it for you. I guess you have this exception because of this parameter : Mockito.any() in your Mockito.when(). It have to be of a Uri type.
Your code will looks like this :
#ExtendWith(MockitoExtension.class)
class ServiceTest {
#Mock
private RestTemplate restTemplate;
#InjectMocks
private RConsumerService refundConsumerService;
#Test
public void sendRequestToBillingService() {
ChargeResponse chargeResponse = new ChargeResponse();
chargeResponse.setInstanceKey("testInstanceKey");
KafkaMessage kafkaMessage = new KafkaMessage();
kafkaMessage.setApplication_id(1L);
kafkaMessage.setCompany_id(1111);
TransactionRequestContext reqContext = refundConsumerService.createTxnRequestContext(kafkaMessage);
URI mockUri = URI.create("http://localhost/mockUri");
Mockito.when(restTemplate.postForEntity(mockUri
, refundConsumerService.buildChargeRequest(reqContext), ChargeResponse.class))
.thenReturn(new ResponseEntity<>(chargeResponse, HttpStatus.OK));
refundConsumerService.refund(kafkaMessage);
assertEquals(chargeResponse.getInstanceKey(), "testInstanceKey");
}
}

Related

How to use MockMvc and Mockito(?) to make my stub return status code 500 or 400?

I'm testing spring controller that sends requests to 3rd party API and I would also like to write a JUnit test that stubs / mocks the API sending back HTTP 500 and 400 responses to see how it handles error answers. Being new to spring and autotesting, it is tough for me to see what I have to do to stub these HTTP 500 responses.
Here is my class with positive test method.
#ExtendWith(SpringExtension.class)
#WebMvcTest
#AutoConfigureMockMvc
#TestPropertySource(locations = "classpath:application-cloud-stub.properties")
#ContextConfiguration(classes = {...})
public class ControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private BisTechnicalChecksClient client;
#Test
public void TestMethod() throws Exception {
ObjectMapper mapper = new ObjectMapper();
ObjectReader reader = mapper.reader().forType(new TypeReference<List<ClientsByAddrWithStartDateResponse>>() {
});
ClientsByAddrWithStartDateRequest request =
mapper.readValue(new File("request_controller.json"),
ClientsByAddrWithStartDateRequest.class);
List<ClientsByAddrWithStartDateResponse> response = reader.readValue(new File(
"response_controller.json"));
when(client.getClientsByAddrWithStartDate(any(ClientsByAddrWithStartDateRequest.class)))
.thenReturn(response);
MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders
.post("get-clients-by-addr-with-start-date")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.header("param1", "value1")
.content(mapper
.writer()
.withDefaultPrettyPrinter()
.writeValueAsString(request)))
.andExpect(MockMvcResultMatchers.status().is2xxSuccessful())
.andReturn();
String stringResponse = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
List<ClientsByAddrWithStartDateResponse> actualResponse = reader.readValue(stringResponse);
List<ClientsByAddrWithStartDateResponse> expectResponse = reader.readValue(new File(
"response_controller.json"));
Assertions.assertThat(actualResponse).isEqualTo(expectResponse);
}
}
I've been trying to find a way to return preset MockHttpServletResponse when stubbed method is called but to no avail so far.
What do I need to change for my stub to return 500 / 400 statuses and work properly?

RestTemplate Junit: Cannot invoke "org.springframework.http.ResponseEntity.getBody()" because "response" is null

I have a spring boot application that makes an API hit of other internal projects using the rest template which works fine and I am writing unit test cases for it but test case if failing due to Unexpected exception thrown: java.lang.NullPointerException: Cannot invoke "org.springframework.http.ResponseEntity.getBody()" because "response" is null
Service
#Service
#Slf4j
public class DynamoDBServiceImpl implements DynamoDBService {
private final RestTemplate restTemplate;
private final HttpHeaders httpHeaders;
private final String jwtHeader;
private final String apiKeyHeader;
private final String dynamodbSysApiKey;
private final String fetchAdminGroupUrl;
public DynamoDBServiceImpl(
RestTemplate restTemplate,
HttpHeaders httpHeaders,
#Value("${header-name.jwt}") String jwtHeader,
#Value("${header-name.api-key}") String apiKeyHeader,
#Value("${dynamodb-sys-api-key}") String dynamodbSysApiKey,
#Value("${dynamodb-fetch-admin-group-url}") String fetchAdminGroupUrl) {
this.restTemplate = restTemplate;
this.httpHeaders = httpHeaders;
this.jwtHeader = jwtHeader;
this.apiKeyHeader = apiKeyHeader;
this.dynamodbSysApiKey = dynamodbSysApiKey;
this.fetchAdminGroupUrl = fetchAdminGroupUrl;
}
#Override
public List<AdminGroupDTO> getAllAdminGroups() {
log.debug("Request to get admin group details with url : {}", fetchAdminGroupUrl);
httpHeaders.set("Accept", MediaType.APPLICATION_JSON_VALUE);
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
httpHeaders.setBearerAuth(CommonUtils.getHeaderFromCurrentHttpRequest(jwtHeader));
httpHeaders.set(apiKeyHeader, dynamodbSysApiKey);
HttpEntity<AdminGroupDTO> request = new HttpEntity<>(httpHeaders);
ResponseEntity<List<AdminGroupDTO>> response =
restTemplate.exchange(fetchAdminGroupUrl, HttpMethod.GET, request, new ParameterizedTypeReference<List<AdminGroupDTO>>() {});
return response.getBody();
}
}
Test
#SpringBootTest(classes = Application.class)
public class DynamoDBServiceTest {
private final RestTemplate restTemplate = Mockito.mock(RestTemplate.class);
private final HttpHeaders httpHeaders = new HttpHeaders();
private final DynamoDBServiceImpl dynamoDBService =
new DynamoDBServiceImpl(
restTemplate, httpHeaders, "Authorization" , "Api-Key", "fake", "https://fake.com");
#Test
void testGetAllAdminGroups() {
List<AdminGroupDTO> adminGroupDTOList = new ArrayList<>();
AdminGroupDTO adminGroupDTO = new AdminGroupDTO();
adminGroupDTO.setAdminGroupId(1L);
adminGroupDTO.setAdminGroupName("fake");
adminGroupDTO.setCountryName("fake");
adminGroupDTOList.add(adminGroupDTO);
ResponseEntity<List<AdminGroupDTO>> responseEntity = new ResponseEntity<>(adminGroupDTOList, HttpStatus.OK);
when(restTemplate.exchange(
ArgumentMatchers.anyString(),
ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.any(),
ArgumentMatchers.<Class<List<AdminGroupDTO>>>any()))
.thenReturn(responseEntity);
assertDoesNotThrow(dynamoDBService::getAllAdminGroups);
}
}
Replace this line of code :
when(restTemplate.exchange(
ArgumentMatchers.anyString(),
ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.any(),
ArgumentMatchers.<Class<List<AdminGroupDTO>>>any()))
.thenReturn(responseEntity);
With this :
when(restTemplate.exchange(
ArgumentMatchers.anyString(),
ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.any(),
ArgumentMatchers.eq(new ParameterizedTypeReference<List<AdminGroupDTO>>() {}))
)
.thenReturn(responseEntity);
And excepption should dissapear.
For futher details you can check this post.

How to test restclient using RestTemplate and JUnit?

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.

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 = []

Usage of #Value properties in mockito test cases

I have a yml file where I am storing my variables. I am accessing these variables in my program by using #Value annotation. The problem comes when I am writing mock test cases for such methods, I get null pointer exception in my test method. I'm not sure where I am going wrong.
I am making use of #TestPropertySource right now. I need the correct way of doing this.
Here is what I have tried so far.
My yml file looks like this, with many properties in it:
car:
services:
clientId: abcde
authTokenUrl: ....
.....
public Class CarExecution(){
#Value("${car.services.clientId}")
private String clientId;
#Value("${car.services.authTokenUrl}")
private String authTokenUrl;
public String getAccessToken() {
HttpHeaders headers = new HttpHeaders();
headers.set(CONTENT_TYPE, "application/x-www-form-urlencoded");
headers.set(ACCEPT, APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>("grant_type=password" + "&client_id=" + clientId ,headers);
ResponseEntity<Access> response = restTemplate.exchange(authTokenUrl, HttpMethod.POST, entity,A.class);
return response.getBody().token_type + " " +
response.getBody().access_token;
}
}
#RunWith(MockitoJUnitRunner.class)
#TestPropertySource(properties = {
"car.services.clientId = clientId ","car.services.authTokenUrl = authTokenUrl",
})
public class CarTest {
#Value("${car.services.clientId}")
private String clientId;
#Value("${car.services.authTokenUrl}")
private String authTokenUrl;
mockServer = MockRestServiceServer.createServer(restTemplate);
HttpHeaders headers = new HttpHeaders();
headers.set(CONTENT_TYPE, "application/x-www-form-urlencoded");
headers.set(ACCEPT, APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>(
"grant_type=password&client_id=null", headers);
authTokenUrl = "";
new ResponseEntity<>("", HttpStatus.OK);
A access = new A();
access.access_token = "token";
access.token_type = "type";
response = new ResponseEntity<>(access, HttpStatus.OK);
Mockito.when(restTemplate.exchange(authTokenUrl, HttpMethod.POST, entity, A.class))
.thenReturn(response);
The problem might be with your Runner class as MockitoJUnitRunner doesn't initialise any beans or #Value annotations.
Spring's answer to it is SpringJUnit4ClassRunner which does these bits for you (documentation here).
Try replacing #RunWith(MockitoJUnitRunner.class) with #RunWith(SpringJUnit4ClassRunner.class).

Categories