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.
Related
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));
My classes is written in Kotlin and here is my SharedPreferenceHandler
class SharedPreferenceHandler(sharedPrefs: SharedPreferences) {
companion object {
var mInstance: SharedPreferenceHandler = SharedPreferenceHandler(getPrefs())
private fun getPrefs(): SharedPreferences {
return Application.mInstance.getSharedPreferences(
"myApp", Context.MODE_PRIVATE)
}
fun getInstance(): SharedPreferenceHandler {
return mInstance
}
}
private var sharedPreferences = sharedPrefs
var accessToken: String?
get() = sharedPreferences.getString(SharedPreference.ACCESS_TOKEN.name, null)
set(token) = sharedPreferences.edit().putString(SharedPreference.ACCESS_TOKEN.name, token).apply()
}
Here is method called in presenter:
override fun reload(vm: ViewModel) {
super.updateViewModel(vm) {
//some stuffs
}
}
Here is my test method:
#Test
public void reload() {
when(SharedPreferenceHandler.Companion.getMInstance().getAccessToken()).thenReturn("234234234234234");
presenter.reload(viewModel);
}
In handler from super.updateViewModel(vm) I call "SharedPreferenceHandler.mInstance.accessToken!!)"
That is what is thrown:
Caused by: java.lang.IllegalStateException:
Application.mInstanc…m", Context.MODE_PRIVATE) must not be null
at
com.zuum.zuumapp.preferences.SharedPreferenceHandler$Companion.getPrefs(SharedPreferenceHandler.kt:18)
at
com.zuum.zuumapp.preferences.SharedPreferenceHandler$Companion.access$getPrefs(SharedPreferenceHandler.kt:14)
at
com.zuum.zuumapp.preferences.SharedPreferenceHandler.(SharedPreferenceHandler.kt:15)
I wanna to get accessToken by calling " SharedPreferenceHandler.mInstance.accessToken!!" in my test class.
Is possible to get that in my test method?
You can't use Android SharedPreferences in unit test, but you can mock your method call by this:
Mockito.`when`(SharedPreferenceHandler.mInstance.accessToken).thenReturn("token")
And return what you need.
You should not test your code this way. You should create an interface for class you want to mock:
interface MySharedPreferences {
fun getAccessToken(): String
}
Let your SharedPreferencesHandler implements this interface. Then in your presenter (or other class you want to test) inject dependencies (f.e. by constructor or framework like Dagger/Kodein) into your object. Then there is possibility to easy mock this interface. I assume in #Before you create class you test - and then just pass as param your mocked SharedPreferencesHandler.
Testing things with static dependencies is possible, but is but tricky (and a lot of people consider static dependencies as anti-pattern). How to do it is described here: How to android unit test and mock a static method
Example:
class MyPresenter(val sp: MySharedPreferences) {
/* some code here */
fun validateToken() {
if (sp.getAccessToken() == "") throw new Exception()
}
}
Like you see sp is injected into this class as parameter. Normally you don't create views/presenters etc. directly in code but by DI framework (like Dagger or Kodein). Anyway, static dependencies are not easy testable. Injected interface-dependencies can be mocked, and you operating not on object, but on behaviors (so it's bigger level of abstraction). So, now in your test all you have to do is:
class MyTest() {
#Mock lateinit var sharedPreferencesMock: MySharedPreferences
lateinit var instance: MyPresenter
#Before
fun setUp() {
instance = MyPresenter(sharedPreferencesMock)
}
#Test
fun testSomething() {
`when`(sharedPreferencesMock.getAccessToken()).thenReturn("myAccessToken")
/* here is your test body */
}
}
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.
I am trying to use a test implementation of a class and using that to be injected to the test using #InjectMocks but it doesn't seem to inject it. I tried using Spy but that did not work and instead created a blank mocked version instead of using the version I created inside my #Before function
Here is my test code below:
#Before
fun setup() {
someFunction = object : SomeFuntionContract {
override fun save(test: String) {
testData = test //breakpoint here but never executes
}
override fun get(): String {
return testData
}
}
}
lateinit var testData : String
#InjectMocks
lateinit var delegator: Delegator
#Spy
lateinit var someFunction: SomeFunctionContract
#Test
fun testSomething{
delegator.retrieve(something)
Assert.assertTrue(someFunction.get() == "hello")
}
SomeFunctionContract.kt is an interface that has save and get functions and SomeFunction is the real implementation test
Inside delegator.retrieve it calls someFunction.get inside it and I am trying to see if it gets called and saves the data.
Make sure you init the creation and injection of the mocks by:
1) Adding #RunWith(org.mockito.junit.MockitoJUnitRunner) on the test class.
or
2) Adding MockitoAnnotations.initMocks(this) to your #Before method.
The #Before method is called after Mockito does its injection magic so, you are overwriting the spy created and used by Mockito. If you want to have your own implementation of the object to be injected (I'm assuming it is SomeFunctionContract) then you have to declare it on the property instead of on the #Before function.
All that said, I think we are missing some context of your code. Can you attach the code for something, Delegator and testData?
Fixed:
initialise the implementation directly in the spy level:
#Spy
lateinit var someFunction: SomeFunctionContract = = object : SomeFuntionContract {
override fun save(test: String) {
testData = test //breakpoint here but never executes
}
override fun get(): String {
return testData
}
}
I am using Mockito to write a simple unit test.
Then, a function under test:
public class MyService {
public void getData() {
executor.execute(new MyRunnable() {
#Override
doTask() {
MyRestClient client = getRestClient();
Response resp = client.getFromServer();
persist(resp.getData());
}
});
}
}
protected MyRestClient getRestClient() {
return new MyRestClient();
}
My test case, I want to test doTask() has run & resp.getData() is persisted:
#Test
public void testGetData() {
MyService spyService = spy(MyService.getInstance());
// mock client
MyRestClient mockedClient = mock(MyRestClient.class);
mockedClient.setData("testData");
// stub getRestClient() function to return mocked client
when(spyService.getRestClient()).thenReturn(mockedClient);
// SUT
spyService.getData();
// run the Runnable task.
Mockito.doAnswer(new Answer<Object>() {
public Object answer(InvocationOnMock invocation) throws Exception {
Object[] args = invocation.getArguments();
Runnable runnable = (Runnable) args[0];
runnable.doTask();
return null;
}
}).when(executor).execute(Mockito.any(Runnable.class));
...
}
As you see above, I stub the getRestClient() function to return a mocked MyRestClient. However when run the test case, it doesn't stub the getRestClient() but run the real function. Why?
[Edit] following comment and review feedback
A rule of thumb is not to mock the class under test. Also your testing will be much easier if your class under test does not use the new keyword. Instead use Factory classes to create objects. There will be no need to use Mockito.spy() only Mockito.mock().
The fact that the following answer requires significant test setup is telling you that MyService has too much reposibility and needs to be simplified. However for the sake of answering your question directly here is how you can refactor your code to support verifying the call to persist() using Mocks.
MyService accepts in the constructor the objects that you will be mocking in your test setup. Having them passed into the constructor allows your JUnit test case to create the Mocks and keep a reference to them for verification later.
public class MyService {
private MyRunnableFactory runFactory;
private MyRestClientFactory restFactory;
private MyRestDao dao;
// inject constructor arguments
public MyService(MyRunnableFactory runFactory, MyRestClientFactory restFactory, MyRestDao dao) {
this.runFactory = runFactory;
this.restFactory = restFactory;
this.dao = dao;
}
public void getData() {
MyRestClient restClient = restFactory.createInstance();
MyRunnable runner = runFactory.createInstance(restClient, dao);
executor.execute(runner);
}
}
MyRunnable is created so that it can be tested in isolation if required. Again we inject the Mock objects into the constructor. It is tempting to inline Runnables as you have written in your question, however you lose the ability to control the new instance being created within you tests.
public class MyRunnable implements Runnable {
private MyRestClient restClient;
private MyRestDao dao;
public MyRunnable(MyRestClient restClient, MyRestDao dao) {
this.restClient = restClient;
this.dao = dao;
}
public void run() {
Response resp = restClient.getFromServer();
dao.persist(resp.getData());
}
}
MyRestDao is created because this is the class that you want to Verify in your test case. I don't see where persist() is defined in your question so we create a Data Access Object (DAO) to implement it.
public class MyRestDao {
public void persist() {
// save to some repository
}
}
Now let's write the test case that uses the above classes. We want to verify that the persist() method has been called
#RunWith(MockitoJUnitRunner.class)
public class MyServiceTest {
#Mock MyRestDao dao;
#Mock MyRestClient restClient;
#Mock MyRunnableFactory runFactory;
#Mock MyRestClientFactory restFactory;
#Test
public void testPersistIsCalled() {
Response expectedResponse = new Response("some data"); // real implementation, not mocked
MyRunnable runner = new MyRunnable(restClient, dao); // real implementation, not mocked
when(restFactory.createInstance()).thenReturn(restClient);
when(runFactory.createInstance(restClient, dao)).thenReturn(runner);
when(restClient.getFromServer()).thenReturn(expectedResponse);
when(restClient.getData()).thenReturn(myRunnable);
// method under test
MyService service = new MyService(runFactory, restFactory);
service.getData();
verify(dao).persist(expectedResponse.getData());
}
}
Note that this test case is brittle because it is tightly coupled to the actual implementation of the MyService class. Ideally you want tests that don't need to know about the internal workings of your class under test.