Mocking RestTemplate postforEntity - unit-testing

I have a service class which looks like -
class A {
#Autowired
RestTemplate restTemplate;
public void method() {
res = restTemplate.postForEntity("http://abc", entity, Employee.class);
resBody = res.getBody();
}
}
Following is the Test Class for it-
class TestA {
#Mock
RestTemplate restTemplate;
#InjectMocks
A obj;
void testMethod1() {
res = ....
when(restTemplate.postForEntity(any(), any(), any()).thenReturn(res);
}
void testMethod2() {
res = ....
when(restTemplate.postForEntity(anyString(), any(), any()).thenReturn(res);
}
}
testMethod1 fails throwing NullPointerException on "res.getBody() from A.method()" while testMethod2 runs successfully
Why is any() not working here while anyString() works? I thought any() works for any data type.

Take a look into the Javadocs for RestTemplate. There are three postForEntity methods:
postForEntity(String url, Object request, Class<T> responseType, Map<String,?> uriVariables)
postForEntity(String url, Object request, Class<T> responseType, Object... uriVariables)
postForEntity(URI url, Object request, Class<T> responseType)
Your mock in testMethod2 catches for sure one of the first both methods. However the mock in your testMethod1 seems to cover the method with an URI as first parameter and well, therefore your restTemplate.postForEntity("http://abc", entity, Employee.class) does not match.
If you are interested in what method is currently mocked, just type a line, e. g. restTemplate.postForEntity(any(), any(), any()) and then just hover over the method in your favourite IDE to see already at compile time, which exact (overridden) method was covered.

My problem was similar, casting null to String worked for me:
when(restTemplateMock.postForEntity((String)isNull(), any(), eq(List.class)))
.thenReturn(responseEntityMock);

Related

Mockito method call stub not working - Mockito.doReturn(false).when(studentServiceImpl).myClass().isValidUser(ArgumentMatchers.anyInt());

adding test cases for getStudent method, this is having internal calls
1- is repository call - stubbing this call working fine
2- validate user call - stubbing this call not working, showing some error and test case failed.
Service Class
#Service
public class StudentServiceImpl implements StudentService {
#Autowired
FakeStudentRepository fakeStudentRepository;
#Override
public Optional<Student> getStudent(int id) {
Optional<Student> student = fakeStudentRepository.getStudent(id);
boolean isValid = myClass().isValidUser(student.get().getId());
if(!isValid) {
return Optional.empty();
}
return student;
}
public MyTestClass myClass() {
return new MyTestClass();
}
}
MyTestClass
public class MyTestClass {
public boolean isValidUser(int id) {
return true;
}
}
Test Class
#SpringBootTest
class StudentServiceImplTest {
#Mock
FakeStudentRepository fakeStudentRepository;
#InjectMocks
StudentServiceImpl studentServiceImpl;
#BeforeEach
public void setup() {
studentServiceImpl = Mockito.spy(StudentServiceImpl.class);
MockitoAnnotations.initMocks(this);
}
#Test
void getStudent() {
Optional<Student> student = Optional.of(Student.builder().id(1).firstName("Rahul").lastName("rahul")
.mobile("XXXXXX").build());
Mockito.doReturn(student)
.when(fakeStudentRepository).getStudent(ArgumentMatchers.anyInt());
Mockito.doReturn(false)
.when(studentServiceImpl).myClass().isValidUser(ArgumentMatchers.anyInt());
Optional<Student> resultStudent = studentServiceImpl.getStudent(student.get().getId());
assertEquals(resultStudent.get().getId(), student.get().getId());
}
}
Error
org.mockito.exceptions.misusing.WrongTypeOfReturnValue: Boolean
cannot be returned by myClass() myClass() should return MyTestClass
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.
The error Message says it: You are mocking studentServiceImpl.myClass() and try to return true. It’s not possible to mock the end of a call chain as you try with your second Mockito expression.
To do what you want requires to mock myClass() first by returning a mocked class instance and mock isValidUser on that.

***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);
}

How to verify some other object was constructed, when using mockito

I have following Java code that I want to test. What I am having difficulty is figuring out how do I verify that call to handleAppVersionRequest , actually constructs AppVersionResponse object. Is there any way to do that using Mockito?
Here code is code for method:
class MyClass {
public void handleAppVersionRequest(String dataStr,
final int dataChannelId) {
String ver = "1.0";
final AppVersionResponse resp = new AppVersionResponse(ver);
Timber.d("Sending data %s", resp.toString());
sendResponse(dataChannelId, getGson().toJson(resp));
}
}
And here is method for test:
#Test
public void testHandleAppVersionRequest() throws Exception {
MyClass presenter = Mockito.spy(new MyClass());
String versionRequestJson = "{\"command\":1}";
when(presenter.getGson()).thenReturn(gSon);
presenter.handleAppVersionRequest(versionRequestJson,0);
// How do I verify that AppResponse object was constructed?
verify(presenter,times(1)).sendResponse(anyInt(),anyString());
}
If you must test the creation of the object during a unit test, you can extract a factory, mock it for your test, and then verify that the create method is called on it.
At the same time, consider spending some time looking at some tutorials for Mockito and unit testing in general, like this one. You should choose one class that is going to be the 'system under test'. Don't spy or mock this class! Instead, pass in mocks as dependencies that you will use to test the behaviour of your class.
Here is a factory extracted from your MyClass:
class AppVersionResponseFactory {
AppVersionResponse create(String version) {
return new AppVersionResponse(version);
}
}
Then the refactored version of your class where the dependencies (Gson and the factory) are passed in through the constructor:
class MyClass {
//dependencies that can now be mocked!
private final AppVersionResponseFactory appVersionResponseFactory;
private final Gson gson;
//pass the mockable dependencies in the constructor of the system under test!
public MyClass(AppVersionResponseFactory appVersionResponseFactory, Gson gson) {
this.appVersionResposeFactory = factory;
this.gson = gson;
}
public void handleAppVersionRequest(String dataStr, final int dataChannelId) {
String ver = "1.0";
AppVersionResponse resp = AppVersionResponseFactory.create(ver);
Timber.d("Sending data %s", resp.toString());
sendResponse(dataChannelId, gson.toJson(resp));
}
}
Now your test looks something like this:
//mocks
AppVersionResponseFactory mockAppVersionResposeFactory;
Gson mockGson;
//system under test
MyClass myClass;
#Before
public void setUp() {
mockAppVersionResposeFactory = Mockito.mock(AppVersionResponseFactory.class);
mockGson = Mockito.mock(Gson.class);
myClass = new MyClass(mockGson, mockAppVersionResposeFactory);
}
#Test
public void testHandleAppVersionRequest() throws Exception {
String versionRequestJson = "{\"command\":1}";
myClass.handleAppVersionRequest(versionRequestJson, 0);
verify(appVersionResposeFactory).create("1.0");
}
Please note that although your question asks for a way to verify the construction of an object, a better test would probably test the final outcome of that method i.e., that sendResponse was called with the correct dataChannelId and correct JSON. You can use the same techniques in this answer to do that i.e., extracting a dependency (perhaps a ResponseSender?), passing it in the constructor for your MyClass, mocking it in the test, then calling verify on it.

Mockito: stub function is not working

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.

How to use dynamic partial mocking with JMockit and Logger interface?

I've been working with JMockit and its admittedly steep learning curve. I'm pretty new with mocking in general so please excuse the ignorance.
I'm trying to mock out the Logger interface so that I can verify the catch statement is working correctly. Call this an exercise in understanding how JMockit works. The implementing class for the Logger interface is Log4jLoggerAdapter so I thought if I passed an instance of that into my Expectations() block, JMockit would use dynamic partial mocking and "see" my logger statement. Instead, I get the following error:
mockit.internal.MissingInvocation: Missing invocation of: org.slf4j.impl.Log4jLoggerAdapter#error(String msg, Throwable t)
The Class Being Tested
public class MyLoggedClass {
private static final Logger LOGGER = LoggerFactory.getLogger(MyLoggedClass.class);
... // Other variables
#Override
public void connect() {
String info = getServiceInfo();
try {
connector = MyConnectionFactory.connect(info);
} catch (Exception e) {
LOGGER.error("Exception connecting to your service with: " + info, e);
}
}
... // Other methods
}
My #Test
public class MyLoggedClassTest {
#Tested
MyLoggedClass myLoggedClass;
#Test
public void myLoggingTest(#Mocked final Log4jLoggerAdapter logger){
new Expectations(MyConnectionFactory.class, logger){{
MyConnectionFactory.connect(anyString);
result = new Exception();
logger.error(anyString, (Throwable)any);
}};
myLoggedClass.connect();
}
I'd detail the other approaches I've tried but this page would turn into a book. This is my best approach. Any ideas?
* Update * (yes, that was quick)
I changed #Mocked to #Cascading and removed the logger field from my Expectations signature and it worked. I don't understand why. Can someone please provide an explanation? Fumbling about until you stumble on something that works but you don't understand is not a recipe for success. See below:
#Test
public void myLoggingTest(#Cascading final Log4jLoggerAdapter logger){
new Expectations(MyConnectionFactory.class){{
MyConnectionFactory.connect(anyString);
result = new Exception();
logger.error(anyString, (Throwable)any);
}};
myLoggedClass.connect();
}
No need for partial mocking in this case, just mock MyConnectionFactory in the usual way. The only tricky part is how to mock the class that implements the Logger interface, considering that it's instantiated from a static class initializer. As it happens, there is a feature in the mocking API for that (using JMockit 1.14):
public class MyLoggedClassTest
{
#Tested MyLoggedClass myLoggedClass;
#Test
public void myLoggingTest(
#Mocked MyConnectionFactory conFac,
#Capturing final Logger logger)
{
new Expectations() {{
MyConnectionFactory.connect(anyString);
result = new Exception();
}};
myLoggedClass.connect();
new Verifications() {{
logger.error(anyString, (Throwable)any);
}};
}
}
With a #Capturing mocked type, any implementation class will get mocked, so the test doesn't need to know about Log4jLoggerAdapter.