How to test spring rest operation exchange - spring

I have a problem with test of my method which use RestOperation exchange method. When i'm trying to mock response i get an error:
ResponseEntity cannot be returned by toString()
toString() should return String
***
If you're unsure why you're getting above error read on.
Due to the nature of the syntax above problem might occur because:
1. This exception *might* occur in wrongly written multi-threaded tests.
Please refer to Mockito FAQ on limitations of concurrency testing.
2. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies -
- with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.
org.mockito.exceptions.misusing.WrongTypeOfReturnValue:
Below is my class, which i want to test
#Component
public class AuthGateway {
#Autowired
AuthorizedHttpEntityFactory authorizedHttpEntityFactory;
#Autowired
RestOperations restOperations;
#Value("${authServer.host}:${authServer.port}/${authServer.validateToken.path}")
private String authPath;
#Value("${authServer.host}:${authServer.port}/basic/check")
private String basicAuthPath;
#Value("${authServer.tokenName}")
private String tokenName;
#Value("${authServer.host}:${authServer.port}/user")
private String userProfileUrl;
#Value("${authServer.host}:${authServer.port}/homeowner")
private String homeownerUrl;
public UnpackedToken authenticate(String token) throws ResourceAccessException, AuthException {
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.add(tokenName, token);
HttpEntity httpEntity = authorizedHttpEntityFactory.getAuthorizedHttpEntity(formData);
Map map = null;
try {
ResponseEntity<Map> entity = restOperations.exchange(authPath, HttpMethod.POST,
httpEntity, Map.class);
map = entity.getBody();
} catch (RestClientException e) {
processError(e);
}
#SuppressWarnings("unchecked")
Map<String, Object> result = map;
return new UnpackedToken(result);
}
and Test class
#RunWith(MockitoJUnitRunner.class)
public class AuthGatewayTest {
private ResponseEntity<Map> entity;
#Mock
private RestOperations restOperations;
#Mock
private LinkedMultiValueMap linkedMultiValueMap;
#Mock
private AuthorizedHttpEntityFactory authorizedHttpEntityFactory;
#Autowired
#InjectMocks
private AuthGateway authGateway;
private String token;
private Integer userId = 1;
private String role = "ROLE_PRO";
private UnpackedToken unpackedToken;
private Map<String, Object> map;
private RestClientException restClientException;
private AuthException authException;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
restClientException = new RestClientException("Test exception");
authException = new AuthException("Test exception");
token = "token-token";
map = new HashMap<>();
map.put("UserId", userId);
map.put("authorities", Collections.singletonList(role));
entity = new ResponseEntity<>(map, HttpStatus.OK);
unpackedToken = new UnpackedToken(map);
}
#Test
public void testAuthenticateSuccessfully() throws Exception {
HttpEntity httpEntity = new HttpEntity("body");
Mockito.when(authorizedHttpEntityFactory.getAuthorizedHttpEntity(any(Map.class))).thenReturn(httpEntity);
Mockito.when(restOperations.exchange(
Mockito.anyString(), Mockito.<HttpMethod>any(), Mockito.<HttpEntity<?>>any(), Mockito.<Class<Map>>any())).
thenReturn(entity);
Mockito.doNothing().when(linkedMultiValueMap).add(any(), any());
assertEquals(this.unpackedToken, authGateway.authenticate(token));
}
What is wrong with this mock?

Weird, when i change mock line into:
Mockito.when(restOperations.exchange(
Mockito.anyString(), Mockito.<HttpMethod>any(), Mockito.<HttpEntity<?>>any(), Mockito.<Class<Map>>any())).
thenReturn(new ResponseEntity<>(map, HttpStatus.OK));
then it starts working properly...

Related

#Mock RestTemplate not returning expected value

I am creating unit test for my service class:
#Service
#Slf4j
public class SsaOpeningService {
#Autowired
private MockDataInitializer mockDataInitializer;
#Qualifier("restHttpsTemplateClient")
#Autowired
private RestTemplate restTemplate;
#Value("${acc-opening-casa.open-ssa}")
private String openSSAaccountUrl;
public CompletableFuture<AccountData> openSsa(
ApplicationDto items,
HttpHeaders headers,
BigInteger cifNo) {
log.info("Initializing headers");
HeaderRequest headerRequest = new HeaderRequest();
HttpHeaders header = headerRequest.initHeader(headers);
CurrentAcctReqBody request = CurrentAcctReqBody.builder()
.cifNo(cifNo)
.currencyType(SGD_CURRENCY)
.acName1(items.getApplicationData().getPersonalDetail().getName())
.productType(SSA_PRODUCT_CODE)
.noOfAccountHolders(BigInteger.ONE)
.accountType(ACC_TYPE)
.transactionRefNo(mockDataInitializer.randomIntInString(9))
.build();
log.info("Setting up entity for calling SSA opening.....");
HttpEntity<CurrentAcctReqBody> entity = new HttpEntity<>(request, header);
CurrentAcctResBody result = null;
try {
result = restTemplate
.postForObject(openSSAaccountUrl, entity, CurrentAcctResBody.class);
} catch (Exception e) {
log.info(e.getMessage());
}
System.out.println(14527);
System.out.println(result);
if(result !=null && result.getError()==null) {
AccountData accountData = AccountData.builder().build();
BeanUtils.copyProperties(result.getRbkAccountDetail(), accountData);
return CompletableFuture.completedFuture(accountData);
}
return null;
}
}
My test class:
#SpringBootTest
#RunWith(SpringRunner.class)
class SsaOpeningServiceTest {
#InjectMocks private SsaOpeningService ssaOpeningService;
#Autowired private MockDataInitializer dataInitializer;
#Mock private MockDataInitializer mockDataInitializer;
private static HttpHeaders headers = new HttpHeaders();
private static HeaderRequest ekycHeaderRequest = new HeaderRequest();
#BeforeAll
public static void init() {
headers = ekycHeaderRequest.initHeader();
}
#Qualifier("restHttpsTemplateClient")
#Mock private RestTemplate restTemplate;
#Test
void createSsa() throws IOException {
CurrentAcctResBody result = JSONUtils
.getObjectFromJson(DCResourceLoader.getResourceAsString("casa/ssa-res.json"), CurrentAcctResBody.class);
ApplicationDto items = ApplicationDto.builder().build();
Application application = dataInitializer.initialize();
BeanUtils.copyProperties(application, items);
when(restTemplate.postForObject(
any(String.class),
eq(HttpEntity.class),
eq(CurrentAcctResBody.class)))
.thenReturn(result);
System.out.println(1452);
System.out.println(result);
when(mockDataInitializer.randomIntInString(any(Integer.class)))
.thenReturn(dataInitializer.randomIntInString(9));
assertThat(ssaOpeningService.openSsa(items, headers, any(BigInteger.class))).isNull();
}
}
I have mocked my RestTemplate to return me the result I want. Problem is, it is not giving me the expected result. I have printed the result in both test class and service class. But in the service class it is always giving me null. I tried to give the most generic parameter when mocking but still doesnt work. The rest is working fine when running unit test EXCEPT for this part. Need assist on this. Thanks all!
#RunWith(MockitoJUnitRunner.class)
class SsaOpeningServiceTest {
#InjectMocks
private SsaOpeningService ssaOpeningService;
#Mock
private MockDataInitializer mockDataInitializer;
#Mock
private RestTemplate restTemplate;
#Test
void createSsa() throws IOException {
// some code
Mockito.when(restTemplate.postForObject(
nullable(String.class),
any(HttpEntity.class),
eq(CurrentAcctResBody.class)))
.thenReturn(result);
// some code
}
}

unable to mock RestTemplate response

I wanted to mock the RestTemplate's result, but with my code below, it always went to do the Http. Can someone please advise? I think I have parts that I did wrongly, please help.
UserServiceTest.java
#RunWith(SpringJUnit4ClassRunner.class)
public class UserServiceTest(){
#InjectMock
#Autowired
UserService userservice;
#Mock
RestTemplate restTemplate;
#Value(${aa.bb.cc})
private String getfromapplicationpropertiesVal;
#Test
public void test1(){
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
String jsonBody = null;
HttpEntity<String> entity = new HttpEntity<>(jsonBody, headers);
String textContent = "result from junit";
ResponseEntity<String> response = new ResponseEntity<>(textContent, HttpStatus.OK);
String url = "http://localhost:8080/test/test.txt";
doReturn(response).when(restTemplate).exchange(
eq(url),
any(HttpMethod.class),
any(HttpEntity.class),
any(Class.class)
);
userservice.test();
}
}
UserService.java
#Service
public class UserService{
#Autowired
HttpHelperService httpHelperService;
public void test(){
String url = "http://localhost:8080/test/test.txt";
String response = httpHelperService.cal(url, HttpMethod.GET);
System.out.println(response);
}
}
HttpHelperService.java
#Service
public class HttpHelperService{
#Autowired
private RestTemplate restTemplate;
public String cal(String url, HttpMethod httpMethod){
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
String jsonBody = null;
HttpEntity<String> entity = new HttpEntity<>(jsonBody, headers);
String response = restTemplate.exchange(url, httpMethod, entity, String.class); //This part kept calling http when run the #Test
}
}
RestTemplateConfig
#Configuration
public class RestTemplateConfig{
#Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
Recommendation in these type of scenario is to use MockRestServiceServer & not mocking restTemplate.
You might do something like this:
#Mock
RestTemplate restTemplate;
#Autowired
MockRestServiceServer mockServer;
#BeforeEach
public void init(){
mockServer = MockRestServiceServer.createServer(restTemplate); //initialization
}
And then invoke mock for your service something like :
mockServer.expect(requestTo(url))
.andExpect(method(HttpMethod.GET))
.andRespond(withSuccess("successOperation"));
-Alternatively, you can just mock your test() method:
when(mockedHttpHelperService).cal(anyString(),HttpMethod.GET).thenReturn("success");

Mocking RestTemplate.exchange() method gives null value

Mocking RestTemplate.exchange() is not working. The Response of restTemplate.exchange() mocking gives null value at BDS Adapter class. My test case is failing with null pointer exception in BDSAdapter class. (response.getStatusCodeValue() gives null pointer exception..Mockito hints
Unused... -> at com..policydetails_adapters.BDSAdapterTest.getInsuranceHoldings(BDSAdapterTest.java:56)
[MockitoHint] ...args ok? -> at com.policydetails_adapters.BDSAdapter.fetchInsuranceDetails(BDSAdapter.java:77)
Below are my classes.
Test Class:
#RunWith(MockitoJUnitRunner.class)
public class BDSAdapterTest {
#InjectMocks
private BDSAdapter bdsAdapter;
#Mock
private BDSFetchInsuranceDetailsRequest bdsFetchInsuranceDetailsRequest;
#Mock
private RestTemplate restTemplate;
#Mock
Environment env;
#Test
public void getInsuranceHoldings() throws InsuranceHoldingsException {
Mockito.when(restTemplate.exchange(
ArgumentMatchers.anyString(),
ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.any(),
ArgumentMatchers.<Class<BDSFetchInsuranceDetailsResponse>>any()))
.thenReturn(sampleBDSCustomerInsuranceHoldings());
BDSFetchInsuranceDetailsResponse bdsFetchInsuranceDetailsResponse = bdsAdapter.fetchInsuranceDetails("MBSG", "S6564318I", "1234", "007");
assertNotNull("response is not null", bdsFetchInsuranceDetailsResponse);
}
public static ResponseEntity<BDSFetchInsuranceDetailsResponse> sampleBDSCustomerInsuranceHoldings() {
BDSFetchInsuranceDetailsResponse bdsResponse = new BDSFetchInsuranceDetailsResponse();
Header header = new Header();
header.setChannelId("MBSG");
header.setMsgId("4aBE50ZrQtjVuXfTyALJ");
bdsResponse.setHeader(header);
ResponseEntity<BDSFetchInsuranceDetailsResponse> response = new ResponseEntity<BDSFetchInsuranceDetailsResponse>(bdsResponse, HttpStatus.ACCEPTED);
return response;
}
}
My Actual class
#Component
public class BDSAdapter {
#Autowired
RestTemplate restTemplate;
#Autowired
BDSFetchInsuranceDetailsRequest bdsFetchInsuranceDetailsRequest;
#Autowired
Environment env;
public BDSFetchInsuranceDetailsResponse fetchInsuranceDetails(String channelId, String customerId,
String insurerCode, String policyNumber) throws InsuranceHoldingsException {
BDSFetchInsuranceDetailsResponse bdsFetchInsuranceDetailsResponse = null;
try {
logger.info("Inside BDSAdapter::fetchInsuranceDetails");
Header header = new Header();
header.setMsgId(RandomStringUtils.randomAlphanumeric(20));
header.setChannelId(channelId);
bdsFetchInsuranceDetailsRequest.setHeader(header);
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add("Accept", MediaType.APPLICATION_JSON_VALUE);
HttpEntity<BDSFetchInsuranceDetailsRequest> requestEntity = new HttpEntity<>(bdsFetchInsuranceDetailsRequest, requestHeaders);
ResponseEntity<BDSFetchInsuranceDetailsResponse> response = restTemplate.exchange(env.getProperty("bds_fetch_insurance_details_url"),HttpMethod.POST, requestEntity, BDSFetchInsuranceDetailsResponse.class);
if(response.getStatusCodeValue() == 204) {
throw new InsuranceHoldingsException(response.getStatusCode().toString(), "No Content");
}
bdsFetchInsuranceDetailsResponse = response.getBody();
} catch (Exception e) {
e.printStackTrace();
}
}
return bdsFetchInsuranceDetailsResponse;
}
}
Perhaps, because mock of BDSFetchInsuranceDetailsResponse will return not a class of BDSFetchInsuranceDetailsResponse but some mockclass
Arugments inside restTemplate.exchange() method should match. In this code env.getProperty("bds_fetch_insurance_details_url") returns null which does not match with String. So it gives null response.
Added the below statment before When(restTemplate.exchange(-,-,-,-).thenReturn(myResponse). It is working
`Mockito.when(env.getProperty("bds_fetch_insurance_details_url")).thenReturn("anyString")`;

Test a method that returns a ResponseEntity from a service class - Spring boot

I have a service method which returns a ResponseEntity<>, when I am testing the rest endpoint it always returns below error.The error says that it haven't return the expected json.
java.lang.AssertionError: No value at JSON path "$.status"
This is the method I'am using
#Test
void Should_ReturnOk_When_VerifyOtpIsSuccessful() throws Exception {
ResponseWrapper responseWrapper =
new ResponseWrapper(ResponseStatusType.SUCCESS, "SUCCESSFULLY_VERIFIED", null);
ResponseEntity<ResponseWrapper> responseWrapperResponseEntity =new ResponseEntity<>(responseWrapper,HttpStatus.ACCEPTED);
when(otpService.verifySmsOtp(otpVerifyRequestDto)).thenReturn(responseWrapperResponseEntity);
this.mockMvc.perform(MockMvcRequestBuilders
.post(OTP_VERIFY_URI)
.contentType(MediaType.APPLICATION_JSON)
.header("app-key", "xxxx")
.content(asJsonString(otpVerifyRequestDto)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.status", is("S")))
;
}
Here ResponseWrapper is a model class
#Getter
public class ResponseWrapper {
private ResponseStatusType status;
private String message;
private String data;
public ResponseWrapper(ResponseStatusType statusType, String message, String data) {
this.status = statusType;
this.message = message;
this.data = data;
}
}
Could you help me out to sort this issue.
Edited:
Seems like the ResponseEntity does not return the JSON itself, it have other objects
Appreciate your input on this.
Test Class Initialization
#AutoConfigureMockMvc
public class OtpControllerTest {
#Mock
private OtpServiceImpl otpService;
private Validator validator = new Validator();
private OtpRequestDto otpRequestDtoEmail = otpRequestDto();
private OtpVerifyRequestDto otpVerifyRequestDto = otpVerifyRequestDto();
#InjectMocks
private OtpController otpController;
private MockMvc mockMvc;
#BeforeEach
void setUp() {
MockitoAnnotations.initMocks(this);
otpController = new OtpController(otpService, validator);
this.mockMvc = MockMvcBuilders.standaloneSetup(otpController).build();
}
// test methods here
//
}
Thank you.

How to mock resttemplate calls in spring boot?

I tried to write test cases for the rest calls in my service which is calling the 3rd party api.
#RunWith(MockitoJUnitRunner.class)
public class ForceServiceTest {
private ForceService forceService;
#Mock
private ForceServiceConfig config;
#Mock
private RestTemplate restTemplate;
#Before
public void setup() {
forceService = new ForceService(config);
}
#Test
public void apiCall_valid() throws JSONException {
HttpHeaders headers = new HttpHeaders();
headers.set(CONTENT_TYPE, "application/x-www-form-urlencoded");
headers.set(ACCEPT, APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>(
"id=null",
headers);
config.authTokenUrl = "https://ex...com/..";
Mockito.when(restTemplate.exchange(config.authTokenUrl, HttpMethod.POST, entity, Access.class)).thenReturn(null);
// Mockito.when(any()).thenReturn(null);
forceService.apiCall();
}
}
#Component
public class ForceService {
private ForceServiceConfig config;
private RestTemplate restTemplate = new RestTemplate();
public ForceService(ForceServiceConfig config) {
this.config = config;
}
private String apiCall() {
HttpHeaders headers = new HttpHeaders();
headers.set(CONTENT_TYPE, "application/x-www-form-urlencoded");
headers.set(ACCEPT, APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>(
"&id=" + config.id,
headers);
ResponseEntity<Access> response = restTemplate.exchange(config.authTokenUrl, HttpMethod.POST, entity,
Access.class);
return response.getBody().token_type + " " + response.getBody().access_token;
}
}
I get the following error:
org.springframework.web.client.HttpClientErrorException: 404 Not Found
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:78)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:700)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:653)
It is calling the api in test class, which I do not want to happen.
I need to mock the resttemplate call of 3rd party api. How can I do it without being actually calling the api?
This is the problem
public class ForceService {
private ForceServiceConfig config;
private RestTemplate restTemplate = new RestTemplate(); // HERE
you are creating new REAL rest template. What you probably want is to
Use mock that you created in wrapping test class
Use real rest template and SPY on it.
A don't know is that your actualy structure (1 file 2 classes) but it is safe to assume it is not and in any case you can simply pass RestTemplate as ctor argument. So
#Component
public class ForceService {
private ForceServiceConfig config;
private RestTemplate restTemplate;
public ForceService(ForceServiceConfig config,RestTemplate restTemplate) {
this.restTemplate=restTemplate;
this.config = config;
}
and
#Before
public void setup() {
forceService = new ForceService(config,restTemplate);
}
Now if you want to RestTemplate to be just a stub that does literally nothing and return null on any calls if not instructed otherwiser - leave it as #Mock.
If you want however, to allow it to work normally and only intercept some specific method calls and stub responses, use spy.
#Mock
private RestTemplate restTemplate;
private RestTemplate restTemplate=Mockito.mock(RestTemplate.class)
or
private RestTemplate restTemplate=Mockito.spy(new RestTemplate());

Resources