Mockito mock is giving null for given test cases - spring-boot

I am using the SpringRunner to run the Junit mockito test case , below is the class , i was trying to write the test case , but getting null object
public class AccountManager {
public String getToken() throws Exception {
#Autowired
RestClient restClient;
String auth = apiUserPrefix + apiUserName + BatchJobConstants.COLON + apiUserPassword;
byte[] encodedAuth = Base64.encodeBase64(
auth.getBytes(StandardCharsets.UTF_8));
String authHeader = BatchJobConstants.BASIC_SPACE + new String(encodedAuth);
String token= null;
MultiValueMap<String, String> data = new LinkedMultiValueMap<>();
data.add("grant_type", "client_credential");
String accManagerUrl = accManagerHost+":"+accManagerPort+"/"+accManagerResPath;
RestResponseObject responseObject = null;
try {
responseObject = restClient.execute(accManagerUrl, HttpMethod.POST, data, String.class, authHeader);
if (responseObject != null && responseObject.getPayload() != null && responseObject.getStatusCode() == HttpStatus.OK) {
JsonElement responseJson = (JsonElement) responseObject.getPayload();
if (responseJson.isJsonObject()) {
token= responseJson.getAsJsonObject().get(BatchJobConstants.ACCESS_TOKEN).getAsString();
}catch(RunTimeException e) {
//e
}
return token;
}
//Junit test case
#RunWith(SpringRunner.class)
public class AccountManagerTest {
#InjectMocks
AccountManager accountManager;
#Mock
RestClient restClient;
#Test
public void getTokenAccMgrSucess() throws Exception {
RestResponseObject restResponseObject = Mockito.mock(RestResponseObject.class);
Mockito.when(restClient.execute(Mockito.anyString(), Mockito.any(HttpMethod.class),
Mockito.anyString(), Mockito.eq(String.class), Mockito.anyString())).thenReturn(restResponseObject);
String token = accountManagerTokenProvider.getToken();
Assert.assertEquals("Token value {} ", null, token);
}
}
But still the below code return null value even after mocking this, can you please help how to mock this.
responseObject = restClient.execute(accManagerUrl, HttpMethod.POST, data, String.class, authHeader);
Note: Only Mockito needs to use no powermockito

For Autowired fields you not only have to mock it but should bind the mocked class to the spring context. You have two options :
1. Mark the mocked class as primary bean
#Configuration
public class TestConfiguration {
#Bean
#Primary
public RestClient restClient() {
return Mockito.mock(RestClient.class);
}
}
2.Use #MockBean annotation
#MockBean
RestClient restClient;
More on this :
https://www.baeldung.com/injecting-mocks-in-spring
https://www.baeldung.com/java-spring-mockito-mock-mockbean

Finally worked with mockito only just user any() instead of anyString(), since the Object is not matching with string only
Mockito.when(restClient.execute(Mockito.any(), Mockito.any(HttpMethod.class),
Mockito.any(), Mockito.eq(String.class), Mockito.any())).thenReturn(restResponseObject);

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
}
}

Mock LocalDate.now() and LocalTime.now() for testing scope

I need to mock the two static methods LocalDate.now() and LocalTime.now() in a testing class.
I'm using PowerMock but I receive this error when I try to run the test:
org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.web.client.RestTemplate]: Constructor threw exception; nested exception is java.lang.NoClassDefFoundError: Could not initialize class javax.xml.transform.FactoryFinder
I had try to create a #Bean of RestTemplate.class inside the test class and configuration class but the error persists.
I have this error only if I run the test with PowerMockRunner.class. If I try to run it with SpringRunner.class everything is fine but I can't mock the LocalDate and LocalTime.
This is my Test class:
#PrepareForTest(LocalDate.class)
#RunWith(PowerMockRunner.class)
#SpringBootTest(webEnvironment = RANDOM_PORT, classes = ChallengeApplication.class)
#ActiveProfiles("test")
public class MockTest {
#Autowired
private TestRestTemplate restTemplate;
private URL base;
#LocalServerPort
int port;
User user = new User("user", "password", "user#test.com");
HttpEntity<User> userRequest = new HttpEntity<>(user);
Mock mock = new Mock(new BigDecimal(20));
HttpEntity<Mock> request = new HttpEntity<>(mock );
#Before
public void setUp() throws MalformedURLException {
restTemplate = new TestRestTemplate();
base = new URL("http://localhost:" + port + "/mock/users");
restTemplate.postForEntity(base.toString(), userRequest, String.class);
restTemplate = new TestRestTemplate(user.getUsername(), user.getPassword());
base = new URL("http://localhost:" + port + "/mock/mocks");
}
#Test
public void wrongUserAuth_ThenFailed() throws IllegalStateException {
restTemplate = new TestRestTemplate("test", "test");
ResponseEntity<String> response = restTemplate.postForEntity(base.toString(), request, String.class);
assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode());
}
#Test
public void createTwoAccountsForTheSameUser_ThenFailed() throws IllegalStateException {
restTemplate.postForEntity(base.toString(), request, String.class);
ResponseEntity<String> responseTwo = restTemplate.postForEntity(base.toString(), request, String.class);
assertEquals(HttpStatus.CONFLICT, responseTwo.getStatusCode());
assertTrue(responseTwo
.getBody()
.contains("mock"));
}
#Test
public void createAccountDuringWeekend_ThenFailed() throws IllegalStateException {
LocalDate date = LocalDate.of(2000, 1, 1);
PowerMockito.stub(PowerMockito.method(LocalDate.class,"now")).toReturn(date);
ResponseEntity<String> response = restTemplate.postForEntity(base.toString(), request, String.class);
assertEquals(HttpStatus.CONFLICT, response.getStatusCode());
assertTrue(response
.getBody()
.contains("mock"));
}
}

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")`;

#MOCK in Junit 5 returns NULL when using #Value in constructor

I am writing test cases for a project which uses File inpurstream at multiple places. Due to the issues with PowerMock and Junit5, I ended up using a Constructor with #Value to pass file paths to the class. Sample code will show.
Now When I use the constructor with #Value. The test cases for File inputStream work perfectly. But #MOck for any other class returns NULL.
I comment the constructor and #Mock starts working.
any One faced this before?
Class to be tested:
#Component
public class test {
TestUtils testUtil;
String nodeConfigFilePath;
String genConfigFilePath;
public test (#Value("${node.config.path}") String nodeConfigFilePath,
#Value("${genConfig.path}", #Autowired TestUtils testUtil) String genConfigFilePath) {
this.nodeConfigFilePath=nodeConfigFilePath;
this.genConfigFilePath= genConfigFilePath;
this.testUtil = testUtil;
}
public boolean filterConfig(JSONObject Json) {
if(testUtil.iterateJsonForPatternMatch(Json))
return true;
else
return false;
}
public void loadConfigFromJson() {
ObjectMapper mapper = new ObjectMapper();
TypeReference<Map<String, String>> typeRef = new TypeReference<Map<String, String>>() {
};
try {
InputStream inputStream = new FileInputStream(nodeConfigFilePath);
Map<String, String> nodeConfig = new HashMap<String, String>();
nodeConfig = mapper.readValue(inputStream,typeRef);
<do something>
}
}
catch(Exception e) {
}
}
}
Test Class:
#ExtendWith(MockitoExtension.class)
public class test {
#InjectMocks
test test;
#Mock
TestUtils testUtil;
#Test
public void testFilterConfig_success() throws Exception{
JSONObject jsonObj = new JSONObject();
when(testUtil.iterateJsonForPatternMatch(jsonObj)).thenReturn(true);
assertEquals(true, test.filterConfig(jsonObj));
}
#Test
public void testloadConfigFromJson_success() throws Exception{
test = new NotificationFilter(nodeConfigFile.getAbsolutePath(),genConfigJsonFile.getAbsolutePath(), testUtil);
test.loadConfigFromJson();
}
}
FYI: I changed the method names and created a dummy class for demo purpose.
So If Now I remove the #Value constructor, It starts working and no Null pointer for testUtil. But testloadConfigFromJson_success() starts to fail. And Vice versa. Can anyone explain why this is the case?
UPDATE: moved autoiring to constructor and passed the TestUtil instance via constructor in Test class. It seems to do the trick. I am not sure if its correct

How to test spring rest operation exchange

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...

Resources