How to write Mockito Junit test cases for Rest template? - unit-testing

From the service I call the third party api using RestTemplate.
#RunWith(MockitoJUnitRunner.class)
public class ForceServiceTest {
#InjectMocks
private ForceService forceService;
#Mock
private RestTemplate restTemplate;
#Before
public void setup() {
forceService = new ForceService(config, restTemplate);
}
#Test
public void createTest_valid() throws JSONException {
/*Mockito.when(restTemplate.exchange(url, HttpMethod.POST, entity, CreateRecordResult.class))
.thenReturn(response);*/
Mockito.verify(restTemplate, Mockito.times(1))
.exchange(Mockito.anyString(),
Mockito.<HttpMethod> any(),
Mockito.<HttpEntity<?>> any(),
Mockito.<Class<?>> any());
forceService.createLead(lead);
}
}
I tried using both the any() method and directly specifying the values. Directly specifying the value in entity seems to be not the right way to test.
Below is the service class that I need to write test cases for.
#Component
public class ForceService {
private RestTemplate restTemplate;
public ForceService(ForceServiceConfig config, RestTemplate restTemplate) {
this.config = config;
this.restTemplate = restTemplate;
}
public String createLead(Lead lead) {
HttpHeaders headers = new HttpHeaders();
headers.set(AUTHORIZATION, getAccessToken());
headers.set(ACCEPT, APPLICATION_JSON);
headers.set(CONTENT_TYPE, APPLICATION_JSON);
LeadWrap leadWrap = new LeadWrap();
leadWrap.setFirstName(lead.getFirstName());
leadWrap.setLastName(lead.getLastName());
leadWrap.setEmail(lead.getEmail());
leadWrap.setPhone(lead.getPhone());
String jsonString;
try {
jsonString = new ObjectMapper().writeValueAsString(leadWrap);
} catch (IOException e) {
throw new RuntimeException(e);
}
HttpEntity<String> entity = new HttpEntity<>(jsonString, headers);
ResponseEntity<CreateRecordResult> exchange = restTemplate.exchange(
config.restUrl + "/v" + config.restVersion + "/sobjects/Lead/", HttpMethod.POST, entity,
CreateRecordResult.class);
if (exchange.getStatusCode().equals(HttpStatus.CREATED)) {
if (exchange.getBody() != null && exchange.getBody().success) {
LOGGER.info("Lead record created with Id " + exchange.getBody().id);
return exchange.getBody().id;
}
throw new RuntimeException("Record is not created");
} else {
LOGGER.error(RETURN_STATUS + exchange.getStatusCode());
throw new RuntimeException(RETURN_STATUS + exchange.getStatusCode());
}
The above test case returns the ResponseEntity exchange as null. Is there any solution for this to make the test case work for RestTemplate exchange call?

The verify needs to go after the call to the production code, in your case the createLead() call. You also are going to want to use matchers for your when call, which probably shouldn't be commented out. In cases like yours you generally don't need both the when and the verify. It just makes the test more complex and harder to read.
I use the verify if there is no return from the service call that I can assert on. In those cases I would wrap all the parameters of the when (if needed to get past a null pointer exception or other error) in any() such as any(HttpEntity.class) or anyString() so the params aren't ambiguous. Then you can use the verify to confirm the actual params are correct. This strategy is easier to maintain. Unfortunately, often it requires an argument captor to verify headers or other params are sent correctly. I say it's unfortunate because the tests become big and messy,
If I can assert on the result I often just use the when. In that case I would wrap the params with eq(), such as eq(httpEntity). In that case the HttpEntity class would need to have a good .equals() method or it would just use the default and probably isn't very helpful. But, it is generally pretty powerful.
You shouldn't use #InjectMocks and initialize in the setup. If you #InjectMocks it creates the instance and injects the mocks. You seem to wan to put a real config in so you would use the setup method or you could mock the config. I used a correct matcher, but you might have to refine them, for example switch some any() to eq() to truly test what you want to test. I also reordered so the action or the call to production call is before the verify. This test should get you started.
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
#RunWith(MockitoJUnitRunner.class)
public class ForceServiceTest {
private ForceService forceService;
#Mock
private RestTemplate restTemplate;
#Before
public void setup() {
forceService = new ForceService(new ForceServiceConfig(), restTemplate);
}
#Test
public void createTest_valid() throws Exception {
when(restTemplate.exchange(anyString(), eq(HttpMethod.POST),
any(HttpEntity.class),
eq(CreateRecordResult.class)))
.thenReturn(new ResponseEntity<>(new CreateRecordResult(), HttpStatus.CREATED));
forceService.createLead();
verify(restTemplate, times(1))
.exchange(eq("config.restUrl/vconfig.restVersion/sobjects/Lead/"),
any(HttpMethod.class),
any(HttpEntity.class),
eq(CreateRecordResult.class));
}
}

You need to tell Mockito what to return when the mock is called...
when(restTemplate.exchange(anyString(), any(), any(), any())).thenReturn(...
Insert the responseEntity you want returned from the call to exchange in the thenReturn.

#DCTID code saved my day. Along with that I faced the below issue and fixed it.
To mock the ResponseEntity's body, I created an object and set value to it. Else, it was not passing this condition - if (exchange.getBody() != null && exchange.getBody().success)
CreateRecordResult createRecordResult = new CreateRecordResult();
createRecordResult.success = true;
Mockito.when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class),
eq(CreateRecordResult.class)))
.thenReturn(new ResponseEntity<>(createRecordResult, HttpStatus.CREATED));

Related

***HELP*** Test/Mock: Service Class using Rest Template, Response and HTTP Entities, Exceptions

I have a service class, with for readability purpose, I have provided the code with dummy variables and objects. I am trying to write a JUNIT test class for the service, primarily with Mockito. No matter how hard I try, I am not able to hit the method serviceMethod irrespective of using spy/mock. I have also included a test, following the main class.
I know I am missing something here, but doesn't cross my mind. I need an eye to review this and let me know how I can write a proper test class for this and obtain coverage for the method.
(P.S. all the necessary imports are in-place and not pasted here to keep this concise)
Thanks in advance!
#Service
public class ServiceClass {
private static final Logger LOGGER = LoggerFactory.getLogger(ServiceClass.class);
#Autowired
String stringUrl;
RestTemplate restTemplate = new RestTemplate();
public void serviceMethod(ModelObject model) {
try {
HttpEntity<ModelObject> request = new HttpEntity<>(model);
ResponseEntity<String> response = restTemplate.exchange(stringUrl,
HttpMethod.POST, request, String.class);
LOGGER.info(response.getBody() + "and " + response.getStatusCode());
} catch (HttpClientErrorException exception) {
LOGGER.info(exception.getResponseBodyAsString());
} catch (HttpStatusCodeException exception) {
LOGGER.info(exception.getResponseBodyAsString());
}
}
Sample Test:
#RunWith(MockitoJUnitRunner.Silent.class)
public class ServiceClassTest {
#InjectMocks
private ServiceClass serviceClass;
#Mock
private RestTemplate restTemplate;
#Test
public void testServiceMethod() {
ServiceClass spy = Mockito.spy(serviceClass);
// ServiceClass spy = mock(ServiceClass.class, Mockito.CALLS_REAL_METHODS);
doNothing().when(spy).serviceMethod(Mockito.any(ModelObject.class));
Mockito.doCallRealMethod().when(spy).serviceMethod(Mockito.any(ModelObject.class));
ResponseEntity<String> responseEntity = new ResponseEntity<>(HttpStatus.ACCEPTED);
Mockito.when(restTemplate.exchange(ArgumentMatchers.anyString(), ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.<HttpEntity<ModelObject>>any(), ArgumentMatchers.<Class<String>>any()))
.thenReturn(responseEntity);
}

spring-boot and mockito test - why is my test failing?

In the application I'm working now, I need to implement a few tests and build upon them. I've been reading and trying out a few things, but haven't had much success.
The goal is to start back-filling with tests the service layer of the application. The first one to be covered is UserService.
So, my idea is to assert the test user we use on the application returns itself. The test class so far is:
#RunWith(MockitoJUnitRunner.class)
#SpringBootTest(classes = {ApplicationMain.class})
public class UserServiceTest {
#Mock
CentralData dataProviderMock;
#InjectMocks
private UserService userService;
private <project>User testUser;
private <project>User mockUser;
#Before
public void init() {
MockitoAnnotations.initMocks(CentralData.class);
System.out.println("dataProviderMock: " + dataProviderMock);
System.out.println("userService: " + userService);
userService = new UserService(dataProviderMock);
testUser = createTestUser();
}
private <project>User createTestUser() {
testUser = new <project>User();
testUser.setSystemId("testuser");
testUser.setEmailAddress("testuser#system.com");
testUser.setFirstName("Test");
testUser.setLastName("User");
// save user
userService.save(testUser);
return testUser;
}
#Test
public void whenUserIdIsProvided_thenRetrievedNameIsCorrect() {
mockUser = userService.getUserById("testuser");
when(userService.getUser("testuser")).thenReturn(testUser);
assertEquals(testUser, mockUser);
}
}
On my UserService, I have this:
public UserService(CentralData dataProvider) {
this.dataProvider = dataProvider;
}
When I save the user, the mocked dataProviderMock logs to the console what I expect it to log. But on the test itself, the mockUser is always null.
I understand the userService does not really accesses the data layer and the database, so mockUser being null is not really wrong. So, how could I perform this test?
I'm pretty sure I'm missing something quite basic here, but can't really see it.

Not able to mock correctly

In a spring-boot application, I do some call to moneris. I would like to mock this part.
In a service class:
#Transactional
#Override
public void saveCreditCard(CreditCardInfoDto creditCardInfo) throws CreditCardException, ResourceNotFoundException {
...
ResolveData resdata = null;
ResolverReceipt resreceipt = null;
...
ResAddCC resAddCC = new ResAddCC(creditCardInfo.getCreditCard(), expirationDate, String.valueOf(paymentGateway.getCryptType()));
resAddCC.setCustId(member.getMemberId().toString());
ResolverHttpsPostRequest mpgReq = new ResolverHttpsPostRequest(paymentGateway.getHost(), paymentGateway.getStoreId(), paymentGateway.getApiToken(), resAddCC);
resreceipt = mpgReq.getResolverReceipt();
resdata = resreceipt.getResolveData();
...
if (resreceipt != null && resreceipt.getResponseCode() != null && Integer.getInteger(resreceipt.getResponseCode()) < 50) {
...
}
When I debug, i see then resreceipt is not null, same thing with resreceipt.getResponseCode() but that do un Null Pointer Exception on this line.
Real value vs Mock?
It seem that unreal call is done to moneris... I would like to avoid that.
In my class test I have:
#InjectMocks
PaymentServiceImpl paymentService;
#Mock
MemberRepository memberRepository;
#Mock
PaymentGatewayConfigRepository paymentGatewayConfigRepository;
#Mock
OperationRepository operationRepository;
#Mock
ResolverReceipt resreceipt;
#Mock
ResolverHttpsPostRequest mpgReq;
#Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
Mockito.when(memberRepository.findOne(memberId)).thenReturn(member);
Mockito.when(paymentGatewayConfigRepository.findAll()).thenReturn(paymentsGateway);
ResolverReceipt resreceipt = new ResolverReceipt("<?xml version=\"1.0\" encoding=\"UTF-8\"?> <receipt> <DataKey>iZxTfRWZaRd3S2lajvoZaPA22</DataKey> <ReceiptId>null</ReceiptId> <ReferenceNum>null</ReferenceNum> <ResponseCode>001</ResponseCode> <ISO>null</ISO> <AuthCode>null</AuthCode> <Message>Successfully registered CC details.</Message> <TransTime>19:13:52</TransTime> <TransDate>2016-12-09</TransDate> <TransType>null</TransType> <Complete>true</Complete> <TransAmount>null</TransAmount> <CardType>null</CardType> <TransID>null</TransID> <TimedOut>false</TimedOut> <CorporateCard>null</CorporateCard> <RecurSuccess>null</RecurSuccess> <AvsResultCode>null</AvsResultCode> <CvdResultCode>null</CvdResultCode> <ResSuccess>true</ResSuccess> <PaymentType>cc</PaymentType> <IsVisaDebit>null</IsVisaDebit> <ResolveData> <cust_id>1</cust_id> <phone>4506777244</phone> <email>paul.smith#gmail.com</email> <note></note> <crypt_type>0</crypt_type> <masked_pan>4242***4242</masked_pan> <expdate>1601</expdate> </ResolveData> </receipt> ");
Mockito.when(mpgReq.getResolverReceipt()).thenReturn(resreceipt);
Basically, you need to create a seam in your code where you can alter the code's behavior without changing the code, itself. Essentially, you inject dependencies, rather than having the code instantiate dependencies so that you can mock dependencies when testing. Presently, in your test code, you're forced to use the real value of resAddCC and mpgReq because the current production code instantiates them via the new keyword, rather than using an injected factory and then calling the factory method on the factory object. Using such a factory, you could mock the factory and its call, where it would otherwise call out to Moneris.

Mockito: Verify if Spring Data JPA delete()-method is called

So, I am relatively new to unit-testing and especially mockito and am trying to figure out how to test the following scenario in Spring WebMVC:
This is my Service Class (simplified):
#Service
public class MyServiceImpl implements MyService {
#Resource
private MyCrudRepository myCrudRepository;
/**
* Method to delete(!) an entry from myTable.
*
*/
#Transactional
public void removeTableEntry(Long entryOid, String userId) throws Exception {
if (myCrudRepository.findOne(entryOid) != null) {
myCrudRepository.delete(entryOid);
log.info("User ID: " + userId + " deleted Entry from myTable with Oid " + entryOid + ".");
} else {
log.error("Error while deleting Entry with Oid: "+ entryOid + " from User with ID: " + userId);
throw new Exception();
}
}
}
Here I call the "built-in" delete-method of Spring Data JPA crudrepository, meaning no custom implementation in the repository itself (Using OpenJPA).
This is my simplified Test-Class:
#RunWith(MockitoJUnitRunner.class)
public class MyServiceImplTest {
final String USERID = "Testuser";
MyServiceImpl myService;
#Mock
MyCrudRepository myCrudRepository;
#Before
public void setUp() {
myService = new MyServiceImpl();
ReflectionTestUtils.setField(myService, "myCrudRepository", myCrudRepository);
}
//works (as expected? not sure)
#Test(expected = Exception.class)
public void testRemoveSomethingThrowsException() throws Exception {
doThrow(Exception.class).when(myCrudRepository).delete(anyLong());
myService.removeSomething(0l, USERID);
}
//does not work, see output below
#Test
public void testRemoveSomething() throws Exception {
verify(myCrudRepository, times(1)).delete(anyLong());
myService.removeSomething(0l, USERID);
}
//...
}
So, I try to verify that delete is called in testRemoveSomething(), but instead I get the following output:
Wanted but not invoked:
myCrudRepository.delete(<any>);
-> at myPackage.testRemoveSomething(MyServiceImplTest.java:98)
Actually, there were zero interactions with this mock.
And I'm nearly out of ideas why, to be honest (thinking about the #Transactional, perhaps? But this didn't get me to the solution, yet). May be that I'm completely wrong here (architectural, dunno) - if so, please feel free to give me a hint :)
It would be great to get some help here! Thanks in advance.
Your method fist calls findOne(), check if that returns something, and then calls delete(). So your test should first make sure that findOne returns something. Otherwise, the mock repository's findOne() method returns null by default. Moreover, you should verify that the call has been executed after it has been executed. Not before.
#Test
public void testRemoveSomething() throws Exception {
when(myCrudRepository.findOne(0L)).thenReturn(new TableEntry());
myService.removeTableEntry(0l, USERID);
verify(myCrudRepository, times(1)).delete(0L);
}
Also, you should use the #InjectMocks annotation rather than instantiating your service and injecting the repository using reflection.

Mock a method call with void return type using JMockit or Mockito

I have a very different kind of method call which I need to test using JMockit testing framework. First let us look at the code.
public class MyClass{
MyPort port;
public registerMethod(){
Holder<String> status=null;
Holder<String> message=null;
//below method call is a call to a webservice in the real implementation using apache cxf framework. This method has a void return type. Read below for better explanation.
port.registerService("name", "country", "email", status, message);
// do some stuff with status and message here.....
HashMap response = new HashMap();
response.put(status);
response.put(message);
return response;
}
}
Now let me explain the a little bit. This class is basically having a port instance variable which is used to connect to a webservice. The webservice implementation uses auto generated apache cxf framework classes to make connection to the webservice and get the response back. My job is to implement the mocking of this webservice call for writing testcases for lot many similar calls that are there in the real application.
The problem here is - If you notice that call to the webservice is actually made by the method port.registerService by sending name, country and email as the parameters. Now we also pass the status and message variables as the parameters themselves to this method. So this method instead of returning some value for status and message, it FILLS IN values in these two passed parameters which is very different from the "RETURN" approach.
Now the problem is when I m trying to mock this call using jmockit, I can always mock this call but what is to be expected ?? as there is no return at all, it turns out to be a void call which fills in values in the parameters passed to it. So I will always get status, and message as null if I mock this call as I cannot state any return expectation in the jmockit implementation.
Please if anybody has any solutions/suggestions to the above problem, do respond and try to help me. Thanks.
I was not sure what the Holder interface looked like so I made some assumptions. But, this is how you mock a method with a void return type using Mockito:
#SuppressWarnings("unchecked")
#Test
public final void test() {
// given
final String expectedStatus = "status";
final String expectedMessage = "message";
final MyPort mockPort = mock(MyPort.class);
final Answer<Void> registerAnswer = new Answer<Void>() { // actual parameter type doesn't matter because it's a void method
public Void answer(final InvocationOnMock invocation) throws Throwable {
// Here I'm stubbing out the behaviour of registerService
final Object[] arguments = invocation.getArguments();
// I don't actually care about these, but if you wanted the other parameters, this is how you would get them
// if you wanted to, you could perform assertions on them
final String name = (String) arguments[0];
final String country = (String) arguments[1];
final String email = (String) arguments[2];
final Holder<String> statusHolder = (Holder<String>) arguments[3];
final Holder<String> messageHolder = (Holder<String>) arguments[4];
statusHolder.put(expectedStatus);
messageHolder.put(expectedMessage);
// even though it's a void method, we need to return something
return null;
}
};
doAnswer(registerAnswer).when(mockPort).registerService(anyString(),
anyString(), anyString(), any(Holder.class), any(Holder.class));
final MyClass object = new MyClass();
object.port = mockPort;
// when
final Map<String, String> result = object.registerMethod();
// then
assertEquals(expectedStatus, result.get("status"));
assertEquals(expectedMessage, result.get("message"));
}
For reference, these are my imports:
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;